问题
I've developed a smallish standalone web app with React and Redux which is hosted on its own web server. We now want to reuse/integrate most parts of this app into another React/Redux web app.
In theory this should work quite nicely because all my React components, reducers and most action creators are pure. But I have a few action creators which return thunks that depend on the app state. They may dispatch async or sync actions, but that's not the issue here.
Let's say my root reducer looks like this:
const myAppReducer = combineReducers({
foo: fooReducer,
bar: barReducer,
baz: bazReducer
});
and my most complex action creators depend on many state slices (luckily there are only a few of those):
const someAction = function () {
return (dispatch, getState) => {
const state = getState();
if (state.foo.someProp && !state.bar.anotherProp) {
dispatch(fetchSomething(state.baz.currentId);
} else {
dispatch(doSomethingSynchronous());
}
};
}
Now the problem is that my action creators expect everything to be inside the root of the state object. But if we want to integrate this app into another redux app we'll have to mount my appReducer with its own key:
// The otherAppReducer that wants to integrate my appReducer
const otherAppReducer = combineReducers({
....
myApp: myAppReducer
});
This obviously breaks my action creators that return thunks and need to read app state, because now everything is contained in the "myApp" state slice.
I did a lot of research and thinking how to properly solve this the last few days, but it seems I'm the first one trying to integrate a Redux based app into another Redux based app.
A few hacks/ideas that came to mind so far:
- Create my own thunk type so I can do
instanceof
checks in a custom thunk middleware and make it pass my thunks a customgetState
function which will then return the correct state slice. - Mount my root reducer with it's own key and make my thunks depend on that key.
So far I think the best approach would be to create my own custom middleware, but I'm not really happy with the fact that other apps will now depend on my middleware and custom thunk type. I think there must be a more generic approach.
Any ideas/suggestions? How would you solve this kind of problem?
回答1:
Have you considered not depending on store.getState()
? I would decouple the actions from the application state altogether and take in the data you need from where the actions are called.
So for example:
const someAction = function (someProp, anotherProp, currentId) {
return dispatch => {
if (someProp && !anotherProp) {
dispatch(fetchSomething(currentId);
} else {
dispatch(doSomethingSynchronous());
}
};
}
This makes the actions totally reusable, with the downside of you having to now have that information elsewhere. Where else? If convenient, inside your component using this.context.store
, or via props
with connect
, or maybe better, by having wrapper actions for your specific applications, so:
const someApplicationAction = () => {
return (dispatch, getState) => {
const { foo, bar, baz } = getState();
dispatch(someGenericAction(foo.someProp, bar.anotherProp, baz.currentID));
};
}
来源:https://stackoverflow.com/questions/35294741/how-to-make-thunks-independent-from-state-shape-to-make-them-portable