Every UI component needs some data to render it. Based on the user interaction, like when a user edits it, some other user changes it or due to external factors, this data may change. The UI component must react to these changes and re-render the UI to show the latest data to the user.
The data used by the UI component is the state of that component. Every application or component will have its own way to manage its state.
State Management helps in updating the UI in related places when there is a change in the application data due to action performed in the application like click, hover, etc. It also helps in making sure that state changes have been incorporated at corresponding places.
As you can see in the above screenshot, we are displaying a list of notifications in the homepage and notification count in the header section, which is common for all the pages in the application. In an application like this, one would fetch the notification count in the header component and the list of notifications in the homepage component.
As you would know, in a typical Single Page Application, the header component is invoked only once, and the content of the page keeps changing when a user navigates between routes. So, if the user moves to a different page and before he comes back to the homepage, a new notification is added by another user. Then, the list on the home page would contain the new set of notifications, but the count will not be updated. As a result, the count and the data on the page are not consistent.
There are many ways to solve this problem. One of them is to use setInterval, setTimeout methods to keep getting the new notification count to display in the header. This is generally considered as a bad practice and this approach may introduce memory leaks.
Alternatively, you can establish a communication between the header component and home component to get the latest notification count. If the communication between the components is direct, then the components will be tightly coupled. Hence, when one component changes, the dependent component is likely to change. To avoid coupling, you may consider writing a shared service to handle the communication between the components. Writing the service in an appropriate way requires additional knowledge and it needs the same amount of knowledge to maintain it.
If the above mentioned two theories don’t work, you may come up with another way to solve this problem. These patterns could vary from project to project. Thus, it increases the onboarding time for a new developer in a project.
Redux provides a single and efficient way to manage the state of the application. Let us understand Redux and see how it helps in addressing the above problems.
Managing State Using Redux
Action: Actions are payloads of information that sends data from your application to your store. They are the only source of information for the store. An action is an object describing the current event occurred in the application.
Reducer: Reducers are just pure functions that take the previous state and an action, and return the next state
Principles of Redux
Single source of truth:
The state of your whole application is stored in an object tree within a single store. It means that there is only one place, which represents state of application and your UI consumes it.
State is read-only:
State is immutable. So, it cannot be modified. If any changes are required, a new object for the state is created.
Changes are made with pure functions:
The only place to manipulate data in Redux is the reducer functions. As the reducers are pure functions, they don’t manipulate the existing data. Instead, they create a new instance of the data with the required changes.
When an action is dispatched, a corresponding reducer is invoked, and a new state object is created based on the action performed.
Redux in Action
Screen-cap from superhero Grider’s “Modern React with Redux”
- When something happens in UI because of which data of the application must be changed, then action creator is invoked to create a new action object
- This action will be passed to dispatch
- Dispatch will read the action object to find the right reducer to be invoked
- Reducer will create a new state object with the required changes based on the action
- The state change will be notified to all the subscribers and the UI will get updated to show the new data
The key takeaway from the way the core concepts and the principles of the Redux system works together is that the pattern establishes a single and precise direction for the data to flow. The purity of the reducer functions increases the predictability of the changes to be made to the data. This behavior not only makes the application easy to understand, but also makes the code easier to test and debug.
As we witnessed, Redux helps in dealing with the actions performed and the changes in data in an efficient way. Though it has a learning curve, it greatly helps in structuring large data driven applications. It could be an overhead to relatively small applications, where the functionality is minimal. So, understanding the need of Redux is important to decide whether to use it or not in your applications.
Innominds is a leading Digital Transformation and Product Engineering company headquartered in San Jose, CA. It offers co-creation services to enterprises for building solutions utilising digital technologies focused on Devices, Apps, and Analytics. Innominds builds better outcomes securely for its clients through reliable advanced technologies like IoT, Blockchain, Big Data, Artificial Intelligence, DevOps and Enterprise Mobility among others. From idea to commercialisation, we strive to build convergent solutions that help our clients grow their business and realise their market vision.
To know more about our offerings, please write to firstname.lastname@example.org