0

I'm using React Boilerplate which uses Redux. I have downloaded the Redux Chrome Dev Tools and I keep getting this error

combineReducers.js:29 The previous state received by the reducer is of unexpected type. Expected argument to be an instance of Immutable.Iterable with the following properties: "route", "language", "global".

I have been debugging this thing through and through to no avail. What I've seen is that combineReducers returns a function and the first line of it is

var inputState = arguments.length <= 0 || arguments[0] === undefined ? _immutable2.default.Map() : arguments[0];

I noticed that a breakpoint here hits twice. The first time, the arguments are exactly what they should be

enter image description here

But the second time my arguments look like this

enter image description here

For some reason, arguments[0] changes from a Map type to a literal object. So two questions:

  • Why does Redux run combineReducers multiple times on INIT?
  • Why would my arguments change when initializing?

Here's the code from store.js in React Boilerplate. I only added the import and call for persistStore.

import { createStore, applyMiddleware, compose } from 'redux';
import { fromJS } from 'immutable';
import { routerMiddleware } from 'react-router-redux';
import createSagaMiddleware from 'redux-saga';
import createReducer from './reducers';
import { persistStore, autoRehydrate } from 'redux-persist';

const sagaMiddleware = createSagaMiddleware();

export default function configureStore(initialState = {}, history) {
    // Create the store with two middlewares
    // 1. sagaMiddleware: Makes redux-sagas work
    // 2. routerMiddleware: Syncs the location/URL path to the state
    const middlewares = [
        sagaMiddleware,
        routerMiddleware(history),
    ];

    const enhancers = [
         applyMiddleware(...middlewares),
    ];

    // If Redux DevTools Extension is installed use it, otherwise use Redux compose
    /* eslint-disable no-underscore-dangle */
    const composeEnhancers =
        process.env.NODE_ENV !== 'production' &&
        typeof window === 'object' &&
        window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
            window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : compose;
    /* eslint-enable */

    //get the state from localStorage
    // const persistedState = loadState();
    const store = createStore(
        createReducer(),
        fromJS(initialState),
        composeEnhancers(...enhancers)
    );

    // Extensions
    store.runSaga = sagaMiddleware.run;
    store.asyncReducers = {}; // Async reducer registry

    // Make reducers hot reloadable, see http://mxs.is/googmo
    /* istanbul ignore next */
    if (module.hot) {
        module.hot.accept('./reducers', () => {
            import('./reducers').then((reducerModule) => {
                const createReducers = reducerModule.default;
                const nextReducers = createReducers(store.asyncReducers);

                store.replaceReducer(nextReducers);
            });
        });
    }

    persistStore(store);

    return store;
}

EDIT

Here is the main reducer file. It brings in other reducer files.

/**
 * Combine all reducers in this file and export the combined reducers.
 * If we were to do this in store.js, reducers wouldn't be hot reloadable.
 */

import { combineReducers } from 'redux-immutable';
import { fromJS } from 'immutable';
import { LOCATION_CHANGE } from 'react-router-redux';

import languageProviderReducer from 'containers/LanguageProvider/reducer';
import globalReducer from 'containers/App/reducer';

/*
 * routeReducer
 *
 * The reducer merges route location changes into our immutable state.
 * The change is necessitated by moving to react-router-redux@4
 *
 */

// Initial routing state
const routeInitialState = fromJS({
    locationBeforeTransitions: null,
});

/**
 * Merge route into the global application state
 */
function routeReducer(state = routeInitialState, action) {
    switch (action.type) {
      /* istanbul ignore next */
      case LOCATION_CHANGE:
          return state.merge({
              locationBeforeTransitions: action.payload,
      });
      default:
        return state;
    }
}

/**
 * Creates the main reducer with the asynchronously loaded ones
 */
export default function createReducer(asyncReducers) {
    return combineReducers({
        route: routeReducer,
        language: languageProviderReducer,
        global: globalReducer,
        ...asyncReducers,
    });
}
Martavis P.
  • 1,708
  • 2
  • 27
  • 45

0 Answers0