When you create a Redux store, its initial state is determined by the root reducer.
In this case, the root reducer is the result of calling combineReducers
on todos
and visibilityFilter
.
const store = createStore(todoApp)
const todoApp = combineReducers({
todos,
visibilityFilter
})
Since reducers are autonomous, each of them specifies its own initial state as the default value of the state
argument.
In const todos = (state = [], action) ...
the default state is an empty array.
The default state value in const visibilityFilter = (state = 'SHOW_ALL', action) ...
is a string.
Therefore, our initial state of the combined reducer is going to be an object containing an empty array under the todos
key, and a string 'SHOW_ALL'
under the visibilityFilter
key:
const todoApp = combineReducers({
todos,
visibilityFilter
})
However, sometimes we want to load data into the store synchronously before the application starts.
For example, there may be Todos left from the previous session.
Redux lets us pass a persistedState
as the second argument to the createStore
function:
const persistedState = {
todos: [{
id: 0,
text: 'Welcome Back!',
completed: false
}]
}
const store = createStore(
todoApp,
persistedState
)
When passing in a persistedState
, it will overwrite the default values set in the reducer as applicable. In this example, we've provided todos
with an array, but since we didn't specify a value for visibilityFilter
, the default 'SHOW_ALL'
will be used.
Since the persistedState
that we provided as a second argument to createStore()
was obtained from Redux itself, it doesn't break encapsulation of reducers.
It may be tempting to supply an initial state for your entire store inside of persistedState
, but it is not recommended. If you were to do this, it would become more difficult to test and change your reducers later.