Manage Component State by Using The useReducer and useCallback React Hooks

Share this video with your friends

Send Tweet
Published 2 years ago
Updated a year ago

We can use the useReducer hook to add a new layer of flexibility to our wizard component by applying the design pattern known as state reducer. This will allow the user of the component to manipulate the inner state of it.

To accomplish this we will need to refactor the component to use the useReducer hook. In this process we will find a bug that we can solve by using the useCallback hook to avoid infinite re-renders.

Instructor: [0:00] We just made the usage of the wizard component a bit more flexible, allowing the user to define how to render their components, but we can go a step further, leading the user to decide how to handle the component state.

[0:12] This design pattern is known as state reducer and is a type of inversion of control. To achieve this, we first have to add logic to our state to allow it to be modified from the outside, but when using useState hook, that logic gets cumbersome. A better option is to use the useReducer hook.

[0:30] UseReducer use the reducer pattern, which is nothing more than a function that allows you to modify the component state based on a specific action. It also uses the initial state, which we will call default initial state. We will create then our reducer function. We will call it the file reducer. This function receives the status and an action.

[0:53] Next, we use desktop student on the state variable to access the active page index value. We will use a simple switch to act on the different actions. For this, we will define an object with the names of the actions.

[1:08] What actions do we have to define? An action to go to the next page, another to go to the previous page, and finally, one to define the number of steps or pages to render. We will use these sections to define our cases.

[1:23] If the action performed is nextPage, then we return a copy of the state using the spread syntax and modify the active page index value by adding one. In case of being prevPage, we only have to modify active page index by subtracting one.

[1:42] Finally, for the setSteps case, we return the status and define the value of the steps attribute using the value obtained from the actions payload.

[1:53] In the main component, we replace the use of useState hook by the useReducer hook which returns a tuple whose first value is the state, and the second value, a function called dispatch that allow action to be dispatched. We will use this dispatch function to modify our functions.

[2:10] In the goNextPage function, we replace our code with a call to dispatch which receives an object with a type attribute whose value will be actions.nextPage. In the goPrevPage function, we will do the same, but the action to be used will be actions.prevPage.

[2:30] We are left to define the setSteps function. We create this function that receives as an argument, a value, n. We call dispatch width and type, actions.setSteps, and a payload attribute with the value of n.

[2:44] Now, our component throws an error. It is rendered multiple times. This happens because the call to the useEffect hook in our wizard pages component is executed multiple times since the list of dependencies constantly changes. In this list, we have setSteps, which is the function that we just defined in wizard. In its new rendering, this function changed.

[3:08] To avoid this, we can make use of a new hook, react.useCallback, which receives, as a parameter, a function, which will be our definition of setSteps, and also a list of dependencies, which in this case is only the dispatch function, which reacts and ensure us that is idempotent, means it will not change.

[3:30] Now, our wizard component works correctly using the useReducer hook, which receives a reducer function and a value for the initial state. The reducer function receives a state and an object that defines the action, and returns the new state.

[3:44] Also, we use the useCallback hook to optimize the rendering behavior of our component by memorizing the function, that is the function is only redefined if one of these dependencies changes. Now, our component code is ready to apply the state reducer pattern.