Become a member
to unlock all features

Level Up!

Access all courses & lessons on egghead today and lock-in your price for life.


    Redux: Supplying the Initial State

    Dan AbramovDan Abramov

    We will learn how to start a Redux app with a previously persisted state, and how it merges with the initial state specified by the reducers.



    Become a Member to view code

    You must be a Member to view code

    Access all courses and lessons, track your progress, gain confidence and expertise.

    Become a Member
    and unlock code for this lesson




    When you create the Redux store, its initial state is determined by the root reducer. In our case, the root reducer is the result of calling combined reducers on todos and visibility filter.

    Since reducers are autonomous, each of them specifies its own initial state as the default value of the state argument, so it's an empty array for the todos reducer, and it's a string to ensure all for the visibility filter reducer.

    The initial state of the combined reducer is going to be an object containing an empty array under the todos key, and show all string under the visibility filter key. This is going to become the initial state of this store, so if we log the current state of the store right after it's graded, we're going to see this object in the console.

    However, sometimes we want to load some existing data into the app synchronously before it starts. For example, we might have persistent todos from the previous session, and we might want to load this slice of the state into the app right before it starts.

    Redux lets me pass the persistent state as the second argument to the create store function, and it will override the value specified by the reducers. If I refresh, I can see that the todos array now has a single item that I specified.

    However, the visibility filter value is still there, and it's still the default value specified by the reducer because it is not in my persistent state object, so the reducer takes control.

    Let's recap and see why this happens. Whatever value we pass to create stores as a second argument is going to end up in the root reducer as the state argument instead of undefined.

    The combined reducer's implementation just forwards the parts of the state to the relevant reducers by their names. This is why the part of the persistent state with the key todos is going to end up as the state object the first time the todos reducer is called instead of undefined.

    Since the state is not undefined, the default argument syntax has no effect, so state stays an array with one item. When Redux initializes the store, it sends an action that won't match any of your custom action types.

    Your reducer is going to fall through to the default case and return the state that it received, and in this case, this state object is the array with one item that we supplied here.

    However, the visibility filter key is not present on the persistent state object, so the parent reducer sees undefined there, and it passes undefined as a state argument to the visibility filter reducer.

    Since the state it receives is undefined, it uses the default argument as specified with ES6 default argument syntax. Just like inside the todos reducer, the action type is not going to match any of the known action types, so it will fall through to the default case and return state.

    But notice that in this case, the state was initialized to show all because it was initially undefined, and so the ES6 default argument syntax kicked in. This explains why the combined reducer returned the initial state containing both the todos that we supplied and the visibility filter supplied by the reducer by default.

    You might get tempted to specify all the initial state tree of your app in a single place and pass it to create store, but we don't recommend this. Co-locating the initial state with the reducer definition makes it easy to test and change, so you should always strive to do that.

    However, you can use the second argument to create store for hydrating persistent data into the store, because it was obtained from Redux itself, so it doesn't break encapsulation of reducers.