I have worked on a couple of projects which had Redux, and i see there is a lot of confusion among people who are getting started. My opinion is if we understand “what problem is redux trying to solve” and “responsibilities of the core components of redux”, life will be easier. This post is my attempt on trying to explain these things.
SPAs(Single Page Applications) these days are pretty complex and they maintain a lot of state in the front end, e.g: api responses, cache data, state of the UI widgets like spinners and progress bars, etc..
Usually we have Models which hold the data and Views which render them. A View can update a single Model or multiple Models, a Model can update another Model and based on these Model changes Views get updated. Because of all these interactions, it becomes difficult to figure out what is actually happening and how the data is flowing.
View Model Problem
The Solution: Unidirectional Data Flow
People thought since the problem arises because of all the criss cross flow of the data, let’s make the data flow unidirectional. Since data flow is just one way, it is easily traceable and the state management becomes more predictable. Facebook popularised this idea through Flux. Let’s take a look at Flux’s architecture
Ok there are a lot of new components over there. Let’s take a look at each one of them in detail
Actions describe what happened in the system. Let us take an example: We have a ToDo app and the user has clicked on a toggle button for a particular todo item. So the corresponding action might look like
Actions usually contain a type and payload. Type specifies what kind of action it is and data contains the payload related to that action. Actions are usually created by something called as Action Creators, it is just a function that formats your input into an Action format(type and data). This provides some de-coupling because the Views now need not know what format the action needs to be. Views just call the Action Creators. Example of an Action Creator
Store is the place where the application state is stored, apart from this the store in Flux also stores the store changing logic. The Store can only be manipulated through actions and cannot be altered directly. Also there can be more than one store with Flux.
Dispatcher is like a router, it sends the actions to the appropriate store.
View Controllers subscribe to the Store and notify the Views when a change occurs in the store.
Yes that is all there is to Flux.
Redux.. but why?
So Redux was created by Dan Abramov for two main reasons
- Hot Reload
- Time Travel Debug
Yes Redux was created mostly for better developer tools.
- In Flux, Store had both the State and State changing logic. In Redux the State changing logic is separated out as Reducers. This is done because if you want to support “Hot code reload” and if both “state changing logic” and “state” live in the same space both will get updated, but with “Hot code reload” we want to update only the “state changing logic” without disturbing the “State”.
- In Flux, Store is mutable, with Redux the Store is immutable and a new object is created on every update. This helps with “Time Travel Debug”.
- There is no separate Dispatcher, the dispatch responsibility is taken the Store.
The Redux architecture looks like
Reducers decide on how the state changes for each action i.e the state changing logic. There can be more than one reducer. Each Reducer is registered with part of the state it is interested in and operates in that scope.
Example of a Reducer to an Action that we discussed earlier
As you can see the Reducer defined above is responsible for the ‘todos’ part of the store object. Initial State is the state at app initialisation, you can set your defaults here. In the body of the function all we are doing is, we are finding the todo item that was toggled and we are changing the completed flag and returning the modified state as a new object. It is very important to note that we are not editing the existing state object, but we are creating a new state object.
That is all there is to Redux, now let us look at an end to end example.
We are dispatching two actions in line 46-47, which will then be sent to reducers, the reducer updates the state and a result the view (in our case it is the console.log) is notified about the store changes and the view is updated.
Usually you use Redux in a setup with React, we will use a connection package like react-redux. React-redux helps React components connect to the Redux store. React and Redux are two separate things, you can use Redux with Vue, Ember or any other View framework.