State management in React with redux vanilla
What’s the state?
I consider the state as a set of modifiable values data that can change with time and directly influence the behavior of your components.
Why do you need to manage your state?
When you are building a large react app and need to share the state between multiple components, you will face some difficulties because by default react allows you to share the state from top to down, from parents to children. That means if you have a child component that’s deeply in your DOM Tree, all the components that are between him and the component that has the state will pass the state down to that component. Remember about our state definition above means that the state influence the behavior of the component that owns it, so each time that a state is edited, the all components in which it’s passed will be rerendered. In this case, it becomes hard for the developers to find out what is happening when something goes wrong, and also it’s a performance issue because of the unuseful renderings. That’s why state management libraries like redux come.
What is Redux?
Redux is a state management library that allows you to centralize your application’s state and gives you tools to share that with among components instead of passing that to your whole Tree. Here is a simple view of how Redux works.
In the next part of this post, we will build a simple to-do app by using Redux for state management, it will help us to understand how redux works and what means each part of the illustration above.
The final result:
For ease of getting started quickly, my example uses Create React App to set up the environment.
Redux requires a few dependencies.
We don’t need react-thunk here because we won’t make calls to an external API.
We are building a simple task management app, a user should be able to see his task list, to create, edit and delete a task.
So let’s get hands-on
By following the redux architecture schema above, we will start by creating the actions of our app, so
What’s an action?
Create the files:
Then move to the taskActions file and create the actions:
Here we create action and an action creator for each feature of our app. Then let’s create the reducer, so
What’s a reducer?
A reducer is a function that takes two parameters: state and action. It returns a copy of the entire state. After receiving an action the reducer can edit the state of the application but the state has to be immutable. Create the reducer in the taskReducer.js file
First, we have imported the actions from the taskActions file, then we create an initialState that contains an isLoading and an empty array of tasks. The taskReducer takes two parameters the state that’s initialized with the initialState and an action. For each action, we’ll make a case, that returns the entire state plus whatever change we're making to it.
Now you have our actions and reducer ready, we need to create the store and connect it to the app.
Let’s create the rootReducer by using the combineReducer function:
In the index file create the store by using createStore method and connect it to the app.
Now we have the whole redux boilerplate setup, the store connects to our application, it’s time to create the UI and we will go with bootstrap for the style! yeah I know I'm a bit old school :)
Each task is characterized by its title, description, and an optional date due. We create a few components that will be used to create and display our task. Start by creating a components folder for them.
A reusable FormInput component that receives, the default value, handleChange, name, label, and finally the type of the input.
The two components above will be used to create the form. We need the last component the TasksTable, that will display our tasks, let’s create it.
Well, now the interesting part comes we gonna bring our all components together and connect them to the redux store. For that, we gonna edit the App.jsx file.
First, we will tackle the creation of a new task. For that we need a task, of course, this task should have an initialState and finally, we need also a function that can update the value of each attribute of the task, remember that our FormInput component above expect handleChange that allows it to update the input value.
The task is set up we can create the form by using our reusables components created above.
Here We have a checkbox whose role is to allow the user to define if the task he is creating has a due date, if so the input date will be displayed below the checkbox. The form is created, now we need to create a submit method to retrieve the new task and send it into our redux store.
At the beginning of this tutorial when we talk about action, we said that actions are the only way to update the store, and we had created an addTask action for the creation. That means here we need to call this action and pass it the task we are creating. we will do that by using the dispatch function so
Dispatch is a method available in the store that accepts an action object. It’s the only way the call an action to update the store. we import dispatch from react-redux.
This function is called when the user submits the form, first, we check if the task he wants to create contains a title and a detail, if so we call dispatch by passing it, the addTask action, and the task that we are creating and at the end we reset the task object with the initial value.
Here is how our form looks like
Now we can create a task we should be able to see the list of the tasks that have been created. We have already created the tasksTable component for this case, we just need to pass it the list of tasks.
Each time we create a new task, we make a call to action and this action saves that into our redux store. That means if we want to display the list of tasks we have to get that from the store. To retrieve a value from the store, we need to subscribe the component to the store and each time this value will be updated the component will have the last value.
To make a subscription we need a function called a selector. again
What’s a selector?
A “selector” is simply a function that accepts the Redux state as an argument and returns data that is derived from that state. In our case, the tasksSelector will take the store as an argument at returns the tasks instead of the whole state because you can have more value in your store.
Redux provides an useSelector hook, that gets a selector as params and returns the value.
Now our component is subscribed to the store and each time a user will create a new task, the component will have the last value. the last thing we have to do is the called the tasksTable and pass it the tasks list for displaying.
Here’s the final result of the App.jsx code:
The code in action:
We did it! I hope you enjoyed this article! To summarize, Redux allows us to easily manage the global state in a React application, it provides you methods and hooks for doing that. If you can check the code source or the demo, you’ll see a lot has been added such as the edition and the deletion of a task, I didn’t add that here to keep the post as short as possible. Please let me know what you think and share the article if it helped you out.
The Nothing 🔺