Redux Toolkitのレビュー
前回の投稿で、従来のReact, Reduxで書いていた部分をRedux Toolkit (RTK) でリファクタしたが、今回はRTKのメソッドについてまとめていく。
Redux Toolkit (RTK) のメソッド一覧
configureStore()
configureStore()
に渡すオプションの型定義を見てみる。
/** * Options for `configureStore()`. * * @public */ export declare interface ConfigureStoreOptions<S = any, A extends Action = AnyAction, M extends Middlewares<S> = Middlewares<S>> { /** * A single reducer function that will be used as the root reducer, or an * object of slice reducers that will be passed to `combineReducers()`. */ reducer: Reducer<S, A> | ReducersMapObject<S, A>; /** * An array of Redux middleware to install. If not supplied, defaults to * the set of middleware returned by `getDefaultMiddleware()`. */ middleware?: M; /** * Whether to enable Redux DevTools integration. Defaults to `true`. * * Additional configuration can be done by passing Redux DevTools options */ devTools?: boolean | EnhancerOptions; /** * The initial state, same as Redux's createStore. * You may optionally specify it to hydrate the state * from the server in universal apps, or to restore a previously serialized * user session. If you use `combineReducers()` to produce the root reducer * function (either directly or indirectly by passing an object as `reducer`), * this must be an object with the same shape as the reducer map keys. */ preloadedState?: DeepPartial<S extends any ? S : S>; /** * The store enhancers to apply. See Redux's `createStore()`. * All enhancers will be included before the DevTools Extension enhancer. * If you need to customize the order of enhancers, supply a callback * function that will receive the original array (ie, `[applyMiddleware]`), * and should return a new array (such as `[applyMiddleware, offline]`). * If you only need to add middleware, you can use the `middleware` parameter instaead. */ enhancers?: StoreEnhancer[] | ConfigureEnhancersCallback; }
reducer
が必須のオプションで、それ以外のmiddleware
, devTools
, preloadedState
, enhancers
は任意となっている。
reducer
部分には、複数のreducerを従来のcombineReducer
の要領でオブジェクト形式で組み合わせて入れることもできれば、単体のreducerを入れることもできる。
combineReducer
でラップして渡すこともできるけど不要。
export default configureStore({ reducer: { todos: todosSlice.reducer, selectedTodo: selectedTodoSlice.reducer, counter: counterSlice.reducer, } }) export default configureStore({ reducer: todosSlice.reducer })
middleware
は、何も渡さなければgetDefaultMiddleware()
が適用される。
もし何らかの理由でそれらのgetDefaultMiddleware()
の適用をしたくなければ、空配列を渡せばよい。
もしくはgetDefaultMiddleware()
に足すかたちでミドルウェアを加えてあげてもよい。
またcombineReducer
でのラップが不要であるのと同じように、applyMiddleware
でラップする必要もない。
export default configureStore({ reducer: { // ... }, middleware: [], }) export default configureStore({ reducer: { // ... }, middleware: [...getDefaultMiddleware(), logger], })
RTKではdevToolsも合わせてついてくるので、出し分け制御もできる。
export default configureStore({ reducer: { // ... }, middleware: : { // ... }, devTools: process.env.NODE_ENV !== 'production' })
大体ここまででほとんどカバーできるだろう。
createSlice()
createSlice()
に渡すオプションの型定義を見てみる。
/** * Options for `createSlice()`. * * @public */ export declare interface CreateSliceOptions<State = any, CR extends SliceCaseReducers<State> = SliceCaseReducers<State>> { /** * The slice's name. Used to namespace the generated action types. */ name: string; /** * The initial state to be returned by the slice reducer. */ initialState: State; /** * A mapping from action types to action-type-specific *case reducer* * functions. For every action type, a matching action creator will be * generated using `createAction()`. */ reducers: ValidateSliceCaseReducers<State, CR>; /** * A mapping from action types to action-type-specific *case reducer* * functions. These reducers should have existing action types used * as the keys, and action creators will _not_ be generated. * Alternatively, a callback that receives a *builder* object to define * case reducers via calls to `builder.addCase(actionCreatorOrType, reducer)`. */ extraReducers?: CaseReducers<NoInfer<State>, any> | ((builder: ActionReducerMapBuilder<NoInfer<State>>) => void); }
公式ドキュメントにはcreateSlice
について下記のように書いてある。
A function that accepts an initial state, an object full of reducer functions, and a "slice name", and automatically generates action creators and action types that correspond to the reducers and state.
action typeはslice名の後にスラッシュ区切りで、合わせて自動で生成してくれる。
initialStateも必須となっているので、従来のように初期のstateの型と値を与えることを忘れることもなくなる。
また、ここが一番の利点思っている点として、immerによりstateをmutableにハンドルすることができるようになる。
だた、immerを使用する際の注意点として、
- immerはあくまで、mutableにinputされた書き方をうまくハンドリングしてimmutableに処理してくれているだけ
- プリミティブ型に対してはmutateできない
- stateのmutateをするか もしくは 新しいstateを返すか のどちらかのみ
もう一つ、prepare
を使用することでactionに渡す前に処理を一回挟めるので、予め渡すオブジェクトを用意する場合などに使える。