Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Redux unexpected key passed to create store

I am getting the error Unexpected key "characters" found in initialState argument passed to createStore. Expected to find one of the known reducer keys instead: "marvelReducer", "routing". Unexpected keys will be ignored.

rootReducer :

 import { combineReducers } from 'redux';
 import { routerReducer } from 'react-router-redux';
 import marvelReducer from './marvelReducer';

 const rootReducer = combineReducers({
   marvelReducer,
   routing: routerReducer
 });
 export default rootReducer;

marvelReducer :

import { FETCH_MARVEL } from '../constants/constants';
import objectAssign from 'object-assign';

export default function marvelReducer(state = [], action) {
  switch (action.type) {
    case FETCH_MARVEL:
      return objectAssign({}, state, {characters: action.data});

    default:
      return state;
  }
}

store :

import { createStore } from 'redux';
import { syncHistoryWithStore } from 'react-router-redux';
import { browserHistory } from 'react-router';

import rootReducer from '../reducers/index';

const initialState = {
  characters: []
};

const store = createStore(rootReducer, initialState);

export const history = syncHistoryWithStore(browserHistory, store);

if (module.hot) {
  module.hot.accept('../reducers/', () => {
    const nextRootReducer = require('../reducers/index').default;
    store.replaceReducer(nextRootReducer);
  });
}

export default store;

I have very similar code in another application and it's working fine. Not sure what's going on here

like image 351
erichardson30 Avatar asked Jun 23 '16 17:06

erichardson30


3 Answers

There's a small mismatch between what you set as the initial state of the store and what you tell the store to expect what the initial state of the store should be, e.g. - update your initial state setting for the store as such:

const initialState = {
   marvel: {
     characters: []
   }
};

And also it's a good idea to name your state tree variable holders to meaningful names that do not contain reducer in them, so update

const rootReducer = combineReducers({
   marvelReducer,
   routing: routerReducer
});

to

const rootReducer = combineReducers({
   marvel: marvelReducer,
   routing: routerReducer
});

And that should do the trick for you.

Hope this helps,

PS. some docs.

From the docs:

If you produced reducer with combineReducers, this must be a plain object with the same shape as the keys passed to it. Otherwise, you are free to pass anything that your reducer can understand.

If you don't need to handle any actions related to one or two, just pull them in initially, this could be as simple as

export default combineReducers({
  events,
  flash,
  one: (state = {}) => state,
  two: (state = {}) => state
})
like image 147
Elod Szopos Avatar answered Sep 20 '22 15:09

Elod Szopos


From the documentation for combineReducers:

The combineReducers helper function turns an object whose values are different reducing functions into a single reducing function you can pass to createStore.

The resulting reducer calls every child reducer, and gathers their results into a single state object. The shape of the state object matches the keys of the passed reducers.

In short, your reducers are configured to handle a state in the form of

{
    marvelReducer,
    routing
}

But you are handing it an initial state in the form of

{
    characters
}

To fix this issue, you will either have to change the keys of the object you pass to combineReducers to include characters, or change the initial state to contain the keys that your reducers are expecting.

like image 23
Michael Parker Avatar answered Sep 19 '22 15:09

Michael Parker


To add to elod answer, The store state object has different properties or different data sections:

{a:data,b:data,c:data}

When you combine reducers, you MUST map each property of the state object to a different reducer

{a:reducerOfDataA,b:reducerOfDataB,c:reducerOfDataC}

This is a mechanism in redux which enforces seperation of data concern for each reducer, reducerOfDataA cannot modify data of reducerOfDataB . This means that all data of reducerOfDataA must sit under {a:...} and not be divided under different properties directly on the root state object {partA1:... , partA2 :...}

Took me entire night to figure this out, hope this little comment will save yours.

like image 26
James Roeiter Avatar answered Sep 20 '22 15:09

James Roeiter