Search code examples
javascriptreduxredux-thunk

Redux: using thunk middleware and combineReducers introduces extra key to getState


Problem: When using thunk middleware before introducing Redux.combineReducers, the getState passed to the thunk correctly returns an object with the correct keys. After refactoring to use Redux.combineReducers, the getState passed to the thunk now returns an object with nested keys. See code below which (hopefully) illustrates my point. This could lead to a potential maintenance nightmare of having to constantly grab the correct key for any thunk method that accesses state.

Question: Is there a simple way to set the correct context key within the thunk? The code feels brittle when I combine reducers and have to insert keys to access the correct state. Am I missing something simple?

Before code:

const Redux = require('redux'),
    Thunk = require('redux-thunk');

// this is an action generator that returns a function and is handled by thunk
const doSomethingWithFoo = function() {
    return function(dispatch, getState) {
        // here we're trying to get state.fooValue
        const fooValue = getState().fooValue;
        dispatch({ type: "DO_SOMETHING", fooValue });
    }
};
// this is a simple action generator that returns a plain action object
const doSimpleAction = function(value) {
    // we simply pass the value to the action. 
    // we don't have to worry about the state's context at all.
    // combineReducers() handles setting the context for us.
    return { type: "SIMPLE_ACTION", value };
}

const fooReducer(state, action) {
    // this code doesn't really matter
    ...
}

const applyMiddleware = Redux.applyMiddleware(Thunk)(Redux.createStore);
const fooStore = applyMiddleware(fooReducer);

After code (introducing a more global appStore):

// need to rewrite my thunk now because getState returns different state shape
const doSomethingWithFoo = function() {
    return function(dispatch, getState) {
        // here we're trying to get state.fooValue, but the shape is different
        const fooValue = getState().foo.fooValue;
        dispatch({ type: "DO_SOMETHING", fooValue });
    }
};


const appReducers = Redux.combineReducers({
    foo: fooReducer,
    bar: barReducer,
});
const appStore = applyMiddleware(appReducers);

Solution

  • After thinking about it some more, I think the answer is to refactor the doSomethingWithFoo action generator so that it accepts fooValue as a parameter. Then I don't have to worry about state object shape changing.

    const doSomethingWithFoo(fooValue) {
        return function(dispatch, getState) {
            // now we don't have to worry about the shape of getState()'s result
            dispatch({ type: "DO_SOMETHING", fooValue });
        }
    }