Understanding Redux
If you have ever worked on a fair-sized React application, using React’s native state management protocols, then chances are you have experienced lifting state and the mess of passing props down various nested levels to child components. In short, this is because React’s information flow only moves up or down the component tree. Parent components can pass down information via props to child components while child components can pass information up via the methods that are passed down to them. But what if a child component wants to pass information to a sibling, or, another component that shares the same parent component? In that case, the child component needs to pass the information up to the parent component to pass it back down to the sibling. As the application scales, sharing and accessing information becomes impractical. Redux is a JavaScript library that offers an alternative approach to managing state and the information flow between components.
To highlight how Redux handles state management I will draw comparisons between Redux and React.
First let’s discuss state. Redux implements the idea of a central store or one state for the entire application, also known as a global state. In contrast to Redux, React can have many states managed by many components. Known as containers, these components utilize state and manage it for themselves and their child components. This also means that there is level of unpredictability due to state change occurring from various places.
So how is state updated? Within the components that manage state, React provides a method or function, depending on the type of component, which allow updating the state. In a class-based component, the “setState” method is used, while in a function-based component, the “useState” function is used. Both update the state by receiving as an argument, the new state with the updated information, and replacing the old state with it. Unlike React, with Redux, components do not update the state directly. Redux provides the components with a function called “dispatch” which serve to send out the information to update the state with. The information that is dispatched is later received and used to update the state. The information that is dispatched is called the “action”.
Already you can see that managing state in Redux requires more steps. This allows for a central, uniform and sychronous flow of information. Components needing to update the global state utilize dispatch functions that send out the action, the information used to update the state. The action is an object which, at the very least, require a property called “type.” Redux’ actions use this property to specify what type of change needs to occur within the global state. Sometimes, in addition to the type property, there are “payloads”, or properties that contain the actual information used to update the state. Another configuration that are used with dispatch functions are what are called “action creators” which are functions that perform operations and then return the action object. Essentially, instead of providing the dispatch function with an actual action object as an argument, you provide it with an invoked function, an action creator, which executes some code and then return the action object after having utilized the result of the executed code. These action creators are highly useful for asynchronous operations. But to recap, when components need to update the global state, they execute dispatch functions, providing them with the action to trigger updates. In order for these updates to occur, the actions are received by other functions called reducers.
Reducers are functions that figure out what updates to make to the global state based on the action that are provided to them by the dispatch functions. Unlike React, where many components can update state, with Redux, only the reducer function can update the global state. The reducer use the type property to trigger a specific update to the global state. Reducers also update the state in an immutable way without mutating the current state, and replacing it with a new state. Once all this is done, the global state is updated and the component will have access to the new state. But how?
With React, the values of the updated state are accessed by the component simply by referencing the property within the state. Redux maintains the uniformity of information flow by not allowing components to directly reach out to the global state to retrieve information. Instead, Redux uses the idea of a subscription where the component needing access to the global state and its information is subscribed to the global state and is provided the information automatically. In implementation, this is carried out by various configurations which allow the component to access the information from the global state via props. In the configuration of a component’s subscription and connection to the global state, there are two important functions, “mapStateToProps” and “mapDispatchToProps.” The mapStateToProps allow the components to access or map the global state’s information via props. The mapDispatchToProps provides the components with the dispatch functions, via props, that will initiate the trigger to update the global state. In this manner, Redux maintains its unidirectional flow of information and transforms state management into a synchronous process. To further illustrate the information flow in Redux:
As you can see from the illustration, Redux implements a synchronous process when managing state as opposed to React, which does so asynchronously. A single event occurs one after the other ultimately resulting in the global state updating. At its core, Redux follows this model but can implement variations which allow for asynchronous processes via middleware like using action creators. Understanding this workflow will allow to implement and follow code more clearly. To learn more, take a look the documentation for Redux.