Sitemap
Knowit Development

Learnings, insights and inspos in tech, design, people, QA and what not as consultants for one of the leading digital consultancy firms in the Nordic region — Knowit. We are experts in systems development. Find us at www.knowit.se

Recreating redux

5 min readSep 22, 2020

--

I had a professor that once said; you can’t fully understand an algorithm until you can code it yourself. This is the first part of a series of articles where we will follow his wise (but maybe not completely true) advise. We will learn some of the most popular tools used in modern front end development by recreating them from scratch. Coming articles will include implementations of module bundling tools, testing frameworks and server side rendering.

Redux is one of the most used, loved, and confusing libraries in modern frontend. It is something that most new React developers stumble upon and can have a hard time wrapping their head around. In this article I will try to explain how Redux works by creating our own lightweight implementation of it.

But first, what is Redux? According to the Redux docs:

“Redux is a predictable state container for JavaScript apps.”

In other words, redux helps you manage state for JavaScript web applications. It’s most commonly used together with React but can be used together with any framework like Vue, Angular or for vanilla applications without any framework at all.

Press enter or click to view image in full size
Redux architecture

Illustrated above are the building blocks of Redux architecture; actions, reducer, store and view. Our custom implementation of Redux will follow the above pattern.

The application state is managed in the store. The state itself is just a plain JavaScript object. The store also provides methods to update the state and read from the state.

Redux is using a publish/subscribe (PubSub) pattern to handle state updates. When a user interacts with the UI, actions can be dispatched (published) to update the state. Views can listen (subscribe) to those updates and modify the UI accordingly. Actions in redux are plain JavaScript objects with a type attribute containing a unique key for the action and a payload attribute containing the data.

Actions can’t update the state themselves, they simple tell the reducers what they should update. All updates are handled by reducers which are pure functions taking the state and action as inputs, applying the action to the state and returning the new state.

Built upon this concepts are the three core principles of Redux:

Single source of truth

The state of your whole application is stored in an object tree within a single store.

State is read-only

The only way to change the state is to emit an action, an object describing what happened.

Changes are made with pure functions

To specify how the state tree is transformed by actions, we write pure reducers (pure = functions that returns a given output for every given input).

It might seem complex at first but after creating or own implementation of redux I hope everything will be a bit more clear. Now, let’s apply what we’ve learned in code!

Creating Redux

We will start off with the full implementation of our Redux store and then break it down into pieces. I think this might come as a surprise for many (it certainly did for me), but we can implement a fully working redux store with 16 lines of code (!).

If we simplify the above, the store looks something like this:

const store = {
state: {}, // a plain object holding our state
listeners: [], // an array containing all listeners (subscribers)
getState: () => {}, // function to get the current state
dispatch: () => {}, // function to dispatch updates to the state
subscribe: () => {}, // subscribe function to add new listeners
}

In the full implementation you can see that everything is happening inside the function create store. This function takes two arguments; reducer and initialState. As mentioned before, reducers are the only ones allowed to change the state. They do so, not by mutating the state, but by returning a new state with the action applied to the previous state. The initialState argument simply lets us create a new store with some predefined data.

Get Joel Gustafsson’s stories in your inbox

Join Medium for free to get updates from this writer.

In our implementation state, listeners, and getState are quite self-explaining. State is simply an object holding our state. Listeners is an array holding all listeners (subscribers) and getState is a function that returns the current state. The subscribe function adds new subscribers to the array of listeners. A subscriber is a function that will be executed every time the state is updated.

That’s it for the store, if you remember our architecture we just need to add a reducer, actions and views to have a fully working implementation.

Reducer and actions

It is in the reducer function that most of the magic happens. Reducer takes the previous state and an action as input (we already know that actions are objects containing a type and a payload). The reducer function will apply the corresponding changes for the action and return a new state. A reducer typically looks something like this:

In this example we have two types of actions to modify the state: ADD and SUBTRACT. If we dispatch an action with the type of “add” the reducer will add the number in the payload to the number in the current state. The reducer then returns the updated state. If we dispatch any other action than add or subtract, the reducer will fallback to the default and return the current state without modifications.

The second part of our dispatch function is the listeners. On every state change, we iterate through the array of listeners and execute each one. By doing this we make sure that all views that are subscribing can update accordingly as the state changes.

store.listeners.forEach((listener) => listener());

That is all for our createStore function. Now we will do a full implementation containing all the building blocks; actions, reducers, store and views.

View

We have already created our store and reducer above. The view in our example is a counter that shows a number and have buttons to perform the actions of adding or subtracting from that number. We achieve this with some simple DOM-elements and a subscriber to our store.

And finally we have the actions and dispatch. This is also mapped to our view — if the user clicks the add or subtract button the corresponding action should be dispatched.

All together we get something like this:

This is not a production ready implementation but it can get you quite far. The redux library covers a lot of edge cases and have a few more advanced features. Especially if you use its react wrapper that comes with hooks and other nice functionalities.

Wrap up

Some tools and libraries that can seem daunting at first are actually quite simple when you break them down. Hopefully this article have given you a basic understanding how Redux works. When you feel ready it might be time to experiment with some of the more advanced features of redux or look into popular design patterns like duck and similar.

--

--

Joel Gustafsson
Joel Gustafsson

Written by Joel Gustafsson

Frontend developer @ Knowit development Stockholm. All about building innovative experiences that makes life easier for users and customers.

Knowit Development
Knowit Development

Published in Knowit Development

Learnings, insights and inspos in tech, design, people, QA and what not as consultants for one of the leading digital consultancy firms in the Nordic region — Knowit. We are experts in systems development. Find us at www.knowit.se