how to set initial state in redux

ReactjsReduxReact Redux

Reactjs Problem Overview


I'm trying to figure out how to set an initial state for a store in redux. I'm using https://github.com/reactjs/redux/blob/master/examples/todos-with-undo/reducers/index.js as an example. I tried to modify the code such that the todos had a value initialized.

const todoApp = combineReducers({
  todos,
  visibilityFilter
}, {
  todos: [{id:123, text:'hello', completed: false}]
})

following the doc: http://redux.js.org/docs/api/createStore.html

but it's not working, and I'm not quite sure why.

Reactjs Solutions


Solution 1 - Reactjs

It needs to be the second argument to createStore:

const rootReducer = combineReducers({
  todos: todos,
  visibilityFilter: visibilityFilter
});

const initialState = { 
  todos: [{id:123, text:'hello', completed: false}] 
};

const store = createStore(
  rootReducer, 
  initialState
);

Solution 2 - Reactjs

You can set the initial state in the reducer(s).

const initialTodos = [{id:123, text:'hello', completed: false}]

// this is the ES2015 syntax for setting a default value for state in the function parameters
function todoReducer(state = initialTodos, action) {
  switch(action.type) {
    ... 
  }
  return state
}


const todoApp = combineReducers({
  // todos now defaults to the array of todos that you wanted and will be updated when you pass a new set of todos to the todoReducer
  todos: todoReducer,
  visibilityFilter
})

Solution 3 - Reactjs

There have been great answers so far but let me ice the cake; perhaps to give you an in-depth analysis, so that you don't just copy StackOverflow codes``` that works but don't know why your program is working.

There are two main ways to accomplish this viz:

  1. using the createStore method. It takes an optional second argument (the preloadedState value)
const store = createStore(counter) // createStore without preloadedState
const initialState = {} // or in your case:
const initialState = {
                         initialTodos = [{id:123, text:'hello', completed: false}]
                     }
const store = createStore(counter, initialState) // create store with preloadedState

if you call createStore without the preloadedState it would initialize the state to {} Hence the reducers will receive undefined as their state values. That brings us to the second method.

  1. You can set it at the reducers. Reducers can also set initialState by looking at the incoming state argument (which would be undefined if createStore is not called with initialState) and returning the values they would like to use as default.
const initialState = {} // a common pattern but in your case:
const initialState = {
                         initialTodos = [{id:123, text:'hello', completed: false}]
                     }
function todoReducer(state = initialState, action) {
  switch (action.type) {
    case // your type:
      return ...
    default:
      return state
  }
}

The drawback of method 2 is evident in a case where there is huge data; like a huge todo list for instance that you want to pass as initialState "app-wide". Method 2 would bring in a lot of repetition as you would have to do the same thing across all your reducers. This is the main drawback. But it is quite popular when you just want to set initialState as {} it is a common pattern.

Here is a 4min read for better understanding: https://dev.to/lawrence_eagles/how-to-properly-set-initial-state-in-redux-78m

Solution 4 - Reactjs

per @ctrlplusb answer, the reason this works is because

const rootReducer = combineReducers({
  todos: todos,
  visibilityFilter: visibilityFilter
});

the first todos is a key which sets the second todos as a return value from the reducer. Reducers always run one time upon store creation. This initializes your global store.

There's an action dispatched when the store is created. That's how the initial state supplied in each combined reducer gets initialized in the store. If you check redux dev tools you'll see the first action dispatched is "@@redux/INIT{something}"

In redux's documentation, near the end of the file, there is a dispatch({ type: ActionTypes.INIT })

See here https://github.com/reduxjs/redux/blob/master/src/createStore.js#L281-L284

See this question/answer I made on stackoverflow clarifying the response: https://stackoverflow.com/questions/55774622/different-ways-of-initializing-a-react-redux-stores-initial-global-state/55774623#55774623

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSaadView Question on Stackoverflow
Solution 1 - ReactjsctrlplusbView Answer on Stackoverflow
Solution 2 - ReactjsjmancherjeView Answer on Stackoverflow
Solution 3 - ReactjsLawrence EaglesView Answer on Stackoverflow
Solution 4 - ReactjsVincent TangView Answer on Stackoverflow