Redux is a powerful integrated framework for React apps to manage their state effectively. We already knew how helpful Redux brings to the big React apps, What Redux do to manage state in React (refer to my blog “Introduction to Redux for React”). In this blog, I am going to introduce step by step for applying Redux into a React app. We will create a react app and discuss how we can integrate Redux into it.
Introduce “HOME INVENTORY” web app
“HOME INVENTORY” app is one of the web applications I made in Web Application Programming in my 3rd semester. It was built in Java with servlet and JSP, and I will convert it into a React app in this blog.
This app's first page is a Login page with a simple layout that includes the username and password text fields for login into the app.
The first component I create is “Login” and using two states for handling username and password fields.
After login, it goes to the main page, this page has a menu with three navigations to “Inventory”, “Admin” pages, and “Logout”. When clicking on “Logout”, it goes back to the “Login” page. The “Inventory” and “Admin” pages use the same template, so their contents are embedded into the main page.
“react-router-dom” is used to navigate between pages, the content of the main page is displayed base on the navigation. For example, when clicking on “inventory”, so the link is “/inventory”. Right after the menu, the “Inventory” component will be rendered.
When creating the “Inventory” component, I don’t need to create the menu again. This component has 2 main parts. First is the table for the list of inventory, and another is the form for entering new inventory. This component has a state to handle inputs for entering a new inventory.
Similar to the “Inventory” component, the “Users” component also has 2 main parts for a list of all users and a form to edit and add a user. This component has a state to handle inputs for the form.
We finished creating UI components for the app. There are states created in these components (“username”, “password”, and “form”), but they are used internally for handling inputs. It means these states no need to be shared with other components, so we don’t need to implement Redux on these states.
1. Understand the states of the app
Our UI components are created but they don’t render any data, such as Inventory and Users. In order for our components to render these kinds of data, they should be a state because the UI will be rendered each time data changed such as when adding a new user or deleting a user, the table of users should be rendered with the new change.
We have new states are inventory and users, so now we consider whether these states should be managed by Redux. The advantage of Redux to share states between components, so if a state is used in many different components, it should be managed by Store in Redux. Let’s look at the Entity Relation Diagram of data in this app.
We can see the Items table link to Categories and Users tables, which means the Item should have info of user and category. Back to our inventory component, when adding a new item, we have to list all categories and users as options for inputs. In addition, both login and the users' components need to use users for authentication and management. Based on these analytics, I know we should have 3 new states ( categories, items, and users ) that should be managed by Store in Redux.
2. Set up Redux for Category
In this app, we don’t need to manage categories, they are used for only showing as options for input in the Inventory components. Therefore, we create only Reducer for Category.
In fact, we should have an action to fetch all categories from server or database to this state stored in Redux. However, in this demo, we don’t use any database management system, so INITIAL_STATE in category reducer is declared with some values.
3. Set up Redux for User
First, we should identify Actions for Users. This app requires features for adding, editing, and deleting a user, so certainly we have to create these 3 actions. We should pass a user as a payload for these actions.
In addition, the login component needs actions for login and logout features, they should have the ability to check if inputted username and password match with any users in Store. Login action needs a different payload, it should be username and password for checking with Users in Store.
Reducer of User will implement appropriate changes for each action on User state that stored in Redux. In detail, this reducer will store 2 states, one is the list of users, and authentication to store the logged-in user. This state’s default value is null, which means no logged-in user. Similar to Category Reducer, we have a default value for users because we don’t use any database management system in this app.
4. Set up Redux for Inventory Item
For the Inventory page, we need 2 features for adding and deleting items, so there are only two actions for Items.
This reducer will store two states, one is for a list of items. We don’t use any database management system, so another state is used for sequence id as the index for id in SQL. The default value of this sequence id is 1, it will be increased by 1 when changing state for adding item action.
Use Store and Dispatch in the components
1. Get authentication from Store in the User reducer
First, the App component (the component wrap entire the app) needs to be added mapStateToProps for getting the currently logged-in user in Store. If this state is not null, it will render the main page component, otherwise, the login component rendered. In the mapStateToProps, the prop of this component will be mapped with the “auth” state stored in the User reducer.
2. Send dispatch to update the currently logged-in user in the User reducer
In the login component, we will use dispatch to send the “Login” action to the User reducer to validate the username and password for login. We should use mapDispatchToProps in order to map props of this component to calls of dispatch we defined.
In the User reducer we set up above, it will check the set of username and password in the payload. If it matches with any user, the currently logged-in user state will be updated to the username in the payload that sent in the action. Otherwise, this state is set to null.
3. Send dispatch to set the logged-in user to null for logout
On the main page, we need to handle the log out in the menu. When clicking on this link, it will send a “Logout” action to the User reducer. In the User reducer we set up above, this action is defined to set a null to the currently logged-in user.
4. Use Store and Dispatch in User component
On User page, we need to access to Store to get all users, so we have to use mapStateToProps for this and map with the props. Also, we need to handle add, edit and delete users, we also need mapDispatchToProps to send appropriate actions for handling these events.
5. Use Store and Dispatch in Inventory component
Similar to the User component, we need to get all Items and handle add, delete items. We need both mapStateToProps and mapDispatchToProps. Besides that, we also need to get the sequenceId in Store for generating the id for new items. Also, inventory items need to refer to the user that is the owner, so mapStateToProps has to have a prop map with the currently logged-in user. Lastly, in order to display categories as options for input, we also need to map a prop with the categories stored in Redux.
In this component, we can see the advantage of Redux. We can access the Store to get any state that should be used for this component and update states in Redux by using dispatch easily.
Now we have a complete Redux React app. Although the setup is the most struggling part in Redux, it’s helpful for managing state when your app is getting bigger. This blog is not showing all steps for setting up or using Store and Dispatch, but we know when building a Redux, we can decide which state should be managed by Redux. And we know how to use Redux basically in a React app.
Here is the GitHub link to full source code of the completed app https://github.com/duythai275/home_inventory