In order to use states of another component, states are passed as a prop through components. However, the React applications manage their components by a tree structure. Therefore, the props, which are used for passing state’s value from a component to other components, may not be used in middle components.
For example: When passing state as a prop from component A to component C as below, the prop should be passed through component B before it reaches component C. However, component B doesn’t need to use that prop.
In case there are many middle components, so we have to repeat passing the props of state values many times. It is really hard to keep track of these states, and maintenance becomes more challenging for us when our React app gets bigger.
Redux solves this problem by not letting components control states. It centralizes all states into a place called “Store”. Instead of passing state as a prop through components, all components can access directly to “Store” to get the appropriate states.
Now, we go deeper on what Redux can help us to manage states and how we set it up.
What Redux is
1. Redux Flow
Redux flow is a one-way binding data flow. There are 3 key concepts in Redux includes Action, Reducer, and Store. “Dispatcher” is the method for passing Actions to Reducer, and Reducer updates State base on Actions. In this Redux flow, Store contains Reducer, so when we want to get data from the state, we have to access the reducer through the store.
Action is what the user does. For example: Click on a button to create an account, the action here is “CREATE_NEW_ACCOUNT” that triggered by the “click” event of the button. In redux, actions are JSON objects, and they must have a “type” property.
Reducer is a function that receives an input that contains the action. The function will return output and this output is the state or the store as we call it in redux. From that, Reducer will define how the data of state changes based on the action.
Store is an abstract concept in Redux, it is a centralized place that holding all states of your React app. Store runs behind in the background (in the core of Redux), we use the Redux API to create Store or get state from Store. That also explains each time when reducers return the new state for Store, it automatically updates the UI base on the updated states.
Making a simple app
These Redux concepts are too complex to understand, and setting up Redux in your project is not an easy part. I spent many times struggling to understand how Redux works. After all, you will see how convenient Redux brings to our life when you actually apply Redux to a large React project. Now let do a simple demo with Redux to know the way how it set up.
1. Installing react-redux
In this article, I will focus on implementing Redux with React, so firstly we should have a React project. If you haven’t had it, you can use “create-react-app” from npm (Node Package Management) to quickly set up your React project. Then, we keep using npm to install Redux for our current React project by using this command.
npm i -S redux react-redux
That’s all we need for installing Redux for a React project.
2. Implementing a react app
In this demo, I will use the example above with 3 components. The state in component A will be passed to component C as a prop. When we change the value of the state in component A, component C will update its UI.
In component A, I have a state called “name”, and it passes the value of this state to component B as props of component B called “name”. Then, component B again passes the props of the state’s value in component A to component C, so component C now can use the state’s value of component A.
It’s just a simple demo with only one middle component (component B) and only one state needs to pass. Let imagine if component C needs more state’s value from component A, or there are many middle components, or component C needs some state’s value from middle components. Can we manage these states? How complex is it now? Remember that is just one-way data, how about if we want to update the state of component A from component C?
3. Setting up Redux concepts
Now we are going to make this demo with Redux, and see how Redux can solve the issue with managing the states between components.
As you may know, Redux takes control of states away from components. Therefore, component A removes the “name” state, and it will be managed in Store of Redux. Before doing this, we need to set up Redux concepts (Action, Reducer, and Store).
Step 1: Create Action
Actions in Redux are objects that carry a payload for Reducer work to update the State. Besides that, Action objects have a Type attribute to define what happens with the State. Our example of Action is for changing the name state with payload which is a new name.
Step 2: Create Reducer
Reducer is a function that takes 2 arguments, they are the current state and an action. Reducer will return the new state base on the action and its operation. Our example of Reducer will change the name in the current state with a new name in the payload of action.
If you divide Reducer into many small Reducers for each State in Store (this structure helps us to manage Reducers more effectively), you should have a root Reducer to combine Reducers.
Step 3: Create Store
The store will hold and update the state of the entire application. To create Store, we use “createStore” method imported from Redux, with an argument which is a reducer. If your app is using a root Reducer, pass it to this method.
Step 4: Wrap the App with Redux Provider
In order to access Store from React, it should be passed to the app with Provider component which will wrap entire the React app with an argument is Store.
We have finished setting up Redux concepts in a React application. So let move on to how we can get data from State in Store and how we can change State.
4. Using Redux in React
React-Redux provides the “connect” method with two arguments are high order functions. The first argument is “mapStateToProps” which used for mapping state to props of the component, and the second argument is optional that named “mapDispatchToProps” which is mapping “Dispatch” to props in order to pass the Action to the Reducer.
4.1 Get State with “mapStateToProps”
This function is to map the State in Store to the props which are used in the component. This function will have an argument that is State in Store. If you are using a root Reducer, this state should refer to the output of the root Reducer.
And this function will return an object with attributes that are mapping with the props in the component.
For example, Component C has a prop named “name” that used to display on Component C, and this “name” prop is mapped to the “name” state in “mapStateToProps” function.
In this example, State in “mapStateToProps” refers to the Root Reducer, so in order to get the “name” state, it has to go through the appropriate Reducer in the Root Reducer.
Remember that we need to connect this “mapStateToProps” with the “ComponentC” component (when exporting the component — the last line in the above example).
4.2 Update State with “mapDispatchToProps
This function is to map high-order functions with props in the component. These high order functions call the “Dispatch” method which is the argument of “mapDispatchToProps”, and the appropriate actions will be passed in “Dispatch” methods.
Similarly with “mapStateToProps”, “mapDispatchToProps” also returns an object with attribute keys which are props in the component.
For example: “updateName” is the prop in “ComponentA” component, it maps with a high order function which calls “Dispatch” to pass the “changeName” Action to Reducer for updating the State. Therefore, in the “ComponentA” component, we use this prop as a function. You see Redux now takes control of the state away from “ComponentA”.
Remember, we should connect the “mapDispatchToProps” to the “ComponentA” component. As the below example, we don’t have “mapStateToProps”, so the first argument of the connect method is null.
Finally, we have a simple Redux-React application.
Github source code: https://github.com/duythai275/my-simple-react-redux-app