问题
In one of the slices in my Redux / RTK store, all I need to to do to make the slice do its job is to create an entity adapter using createEntityAdapter() and export the setAll CRUD function. So far, so simple - thanks to RTK :-)
However, when data for that slice comes in, I need to "augment" it (or "enhance" it, as Redux docs call it), i.e. add further information derived from data coming in, for example for formatted data displayde in the UI (contrived example).
I created an enhancer for that purpose with the goal that the application can rely on data in that slice being complete as soon as it is added, i.e. containing any data required by the components of the app from the very start. (This comes from a previous, unsuccessful approach using a non-UI component that listened to store updates and enhanced slice data afterwards - which lead to update / timing issues.)
In the enhancer, I intercept the action that's of interest and modify the payload before it's added to the store (in the sample code below, I'm only logging the action, but you get the idea...):
export const mySliceEnhancer = (createStore) => {
return (rootReducer, preloadedState, enhancers) => {
const store = createStore(rootReducer, preloadedState, enhancers)
function newDispatch(action) {
// intercept only actions related to my slice
if (action.type === 'mySlice/setAll') {
console.debug('mySliceEnhancer > newDispatch > action.payload:\n' +
JSON.stringify(action.payload, null, 2));
}
const result = store.dispatch(action);
return result;
}
return { ...store, dispatch: newDispatch }
}
}
This works, but is applied globally to the entire store, i.e. dispatch
is "overwritten" with my custom version for any dispatch to the store. This concerns me because for example I lose trace functionality in the Redux Dev Extension: For any dispatch
, the one in my enhancer is shown, no matter if it actually changed anything or not.
Q: Is there any way to apply an enhancer to only one slice of the redux store ?
Or - asking more generally - is my approach a good idea at all ?
回答1:
I think this is a misunderstanding of what enhancers are meant to be used for.
First, enhancers always wrap the entire store object, and have the ability to supply their own versions of store methods like dispatch
.
Second, "slice reducers" are a concept that is irrelevant to the store-level code itself. Remember that you really only have one reducer - the root reducer that you passed to configureStore
. How that root reducer then chooses to split up the work internally doesn't matter to the rest of the store - it could be one giant function with a big series of if
statements that deal with the entire state tree at once, or use combineReducers
to split up the work by top-level keys.
Third, using an enhancer shouldn't wipe out trace functionality if you've configured the store correctly. Per the docs, you can use compose()
to combine multiple enhancers. If you're using RTK's configureStore
, you can pass an enhancers
array and it will take care of composing them together with the DevTools enhancer correctly.
Finally, since all you're really doing is looking for a specific action and modifying its contents, you don't need an enhancer. A middleware will do this just fine:
const myCustomMiddleware = storeAPI => next => action => {
if (action.type === 'mySlice/setAll') {
const state = storeAPI.getState();
action.payload.someField = state.someValue;
}
return next(action);
}
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(myCustomMiddleware);
})
来源:https://stackoverflow.com/questions/65126859/redux-rtk-create-enhancer-for-one-slice