Redux Source Review Part I: createStore

Ben Brostoff
4 min readApr 21, 2018

--

I want to take a different approach to learning frameworks — using a bottom-up approach instead of top-down one. I’m going to review the Redux source code at the latest release as of this writing (4.0) instead of the API docs.

Redux seems like an ideal project to conduct this experiment on because the codebase is relatively small (6 files outside of utils in lib, all < 300 lines and 4 files < 100 lines) with few dependencies (just two non-dev). In the process of reviewing the code, I hope to gain insight into the thought process of the authors and the reasons Redux has had such a huge impact on front-end developers.

I have been using React for about two years now, but have never used Redux for a major project. I am committed to learning Redux over the next few months and using it for a small side project. In my early experiments with Redux, I was delighted to find no front-end framework is necessary. Redux can be used in a Node project without issue. Because experimenting outside of the browser leads to fewer distractions — no consideration of the DOM or browser APIs is necessary — this blog series will use a command-line app in Node as the project that invokes the Redux source.

This first blog post in the series will focus on Redux’s createStore, and use a dumb counter command line application to discuss the Redux store. createStore only requires one argument (reducer), and can optionally take a preloadedState and enhancer. For now, I’m only going to pass the required reducer argument to createStore. The Redux source code describes this argument as follows:

@param {Function} reducer A function that returns the next state tree, given the current state tree and the action to handle.

And what does createStore return?

Creates a Redux store that holds the state tree.

The only way to change the data in the store is to call dispatch() on it.

Let’s trace the source code with only the reducer argument. createStore first checks that reducer is a function. Not passing a reducer that’s a function throws an error:

const { createStore } = require(‘redux’);createStore();// Error: Expected the reducer to be a function.

That makes sense, as no function means no way to input a state tree and output a new state tree.

The source then initializes 5 variables via let — meaning these variables can be set to different values without error — and 6 functions:

I plan to eventually review all of these in future posts, but for now I’ll simply discuss what happens when createStore is invoked. After declaration of these variables and functions, a call to dispatch is made (dispatch({ type: ActionTypes.INIT })) before the function returns an object. The comment above the initial dispatch reads as follows:

When a store is created, an “INIT” action is dispatched so that every reducer returns their initial state. This effectively populates the initial state tree.

ActionTypes.INIT is the string @@redux/INIT (note that in the 4+ releases this also includes a randomly generated alphanumeric string, like 3.o.k.a.q.1.v.5.x.q.s.b.6.r.d.i.y.6.6.r). The Redux source notes about these action types:

These are private action types reserved by Redux.

For any unknown actions, you must return the current state.

If the current state is undefined, you must return the initial state.

Do not reference these action types directly in your code.

I don’t expect my code to be familiar with the action type @@redux/INIT, so my reducer should return the initial state on first call and current state on subsequent calls — this makes sense, as the code comment before the first dispatch says its purpose is for every reducer to return its initial state.

This first dispatch call can be seen when creating a Redux store. I’ve set a breakpoint on my simple reducer within createStore, and here’s what the first invocation looks like:

First dispatch call (note using redux@3.7.2)

My store is ready to be returned following this dispatch call. The returned object has 5 keys (dispatch, subscribe, getState, replaceReducer and a Symbol(observable)), all of which have function values.

getState is a simple function that just returns currentState (one of the aforementioned declared variables that is referenced by the other functions).

Note that getState first checks that a reducer is not executing; this check happens multiple times in the store API, and we’ll explore why it exists in future posts.

On the dispatch call in createStore, currentState is set to the result from invoking the reducer passed to createStore:

Based on what we know about createStore, writing a simple command line app that asks for a number from user input and logs it the console is simple enough:

In the next post, I want to discuss dispatch calls after the initial one and subscribe. I’ll explore these Redux features by building the command line app out to allow various manipulations of user input.

Like this post? Check out my blog, subscribe to my reading recommendation newsletter or let’s get in touch about consulting, pair programming, or anything tech-related on your mind.

--

--