Reduxでの開発では、しばしばAction定義の肥大化に悩まされます。
冗長な記述をなくすライブラリが色々あるようですが、TypeScriptベースのts-actionがとても良さそうだったので、「Angular + @ngrx」での使い心地を見てみました。
通常のコード
// Action
enum BookActionTypes {
SEARCH = "[Books] Search",
SEARCH_COMPLETE = "[Books] Search Complete",
SEARCH_ERROR = "[Books] Search Error"
}
class Search implements Action {
readonly type = BookActionTypes.SEARCH;
constructor(public payload: string) {}
}
class SearchComplete implements Action {
readonly type = BookActionTypes.SEARCH_COMPLETE;
constructor(public payload: Book[]) {}
}
class SearchError implements Action {
readonly type = BookActionTypes.SEARCH_ERROR;
constructor(public payload: string) {}
}
type All = Search | SearchComplete | SearchError;
// Dispatch
store.dispatch(new Search("hello"));
// Reducer
function reducer(state: State = initialState, action: All): State {
switch (action.type) {
case BookActionTypes.SEARCH:
return { ...state, query: action.payload };
case BookActionTypes.SEARCH_COMPLETE:
return { ...state, books: action.payload };
case BookActionTypes.SEARCH_ERROR:
return { ...state, error: action.payload };
default:
return state;
}
}
ts-actionを使用したコード
// Action
const Search = action("[Books] Search", payload<string>());
const SearchComplete = action("[Books] Search Complete", payload<Book[]>());
const SearchError = action("[Books] Search Error", payload<string>());
const All = union(Search, SearchComplete, SearchError);
// Dispatch
store.dispatch(new Search("hello"));
// Reducer
function reducer(state: State = initialState, action: typeof All): State {
switch (action.type) {
case Search.type:
return { ...state, query: action.payload };
case SearchComplete.type:
return { ...state, books: action.payload };
case SearchError.type:
return { ...state, error: action.payload };
default:
return state;
}
}
なかなか良さそうです。
P.S. @ngrx本家にFeature requestを送ったようですが、残念ながら良い返答は得られなかったようです。(https://github.com/ngrx/platform/issues/584)