useCallback hook and react.Memo to improve the rendering of our components
In the following post we are going to use useCallback hook to memorize a function and use it with react.memo, to optimize the rendering of the components, and not to render if they have not had changes.
About the project
The project consumes an API that checks if a name is male and female. What we will do is to keep a history of the queries we made.
The project can be downloaded from https://github.com/sierra-oe/Redux-ReactJS-Http-Request
We use React.Memo to avoid rendering the table completely every time we add a component. In this sense we have optimized the application. But we still need to implement the deletion of the history.
Important
In the following images a green line will be shown, which indicates which components are rendered again at the moment of making a change in the states. As shown below
The image shows that only the component where we show the current query and the history was rendered. It is important to notice that in the history the complete component was rendered, but NOT EVERY ELEMENT OF THE LIST WAS RENDERED, which indicates that we are using react.Memo correctly.
Implementing the function of deleting history items
To implement our history deletion function we must decide where we will write the mass. For this let’s evaluate the project component tree. This tree is according to the previous image.
We have two options to handle the elimination function:
- Within each element of the list, it is not recommended to change states within elements that we memorize to avoid any possible error with the state.
- Inside the GenderList component, it is the best option and here we will implement it in this example. We will share the function that has to delete de item by the props to the children.
import React from "react";
import { useSelector } from "react-redux";
import { Article } from "../UI/Article";
import GenderItem from "./GenderItem";
import classes from "./GenderList.module.css";
import { genderlistActions } from "../../store/genderlist-slice";
import { useDispatch } from "react-redux";
const GenderList = () => {
const buttonDeleteHandler = (idItem) => {
dispatch(
genderlistActions.removeItem({
id: idItem,
})
);
}
const genderListItems = useSelector((state) => state.genderlist.list);
return (
<Article className={classes.article}>
<h2>History of consulted names</h2>
<ul className={classes.list}>
{genderListItems.map((item) => (
<GenderItem
key={item.id}
buttonDeleteHandler={buttonDeleteHandler}
text={item.text}
id={item.id}
/>
))}
</ul>
</Article>
);
};
export default GenderList;
In the previous code we show our handler. To the button of the component GenderItem we will add the property onClick that we will pass through the handler in the props.
The problem
Now that we use the deletion handler we realize that when we add or delete an element it renders each item in the history.
In the following image we will add an element
In the following image we will delete an element
As we can see in the images at the moment, every time we add or delete an element, it re-renders all the items in the list because it recognizes that they have changed.
Reason for the problem
The problem arises because as the list component is completely recreated by the change we made, React recognizes that the handler function of the deletion changed, so each element of the list is different because they are making a call to a different function.
The problem solution
To solve this problem we can use the HOOK “useCallback” which allows us to store a function and not create a new memory space each time the component is reloaded.
import React, { useCallback } from "react";
import { useSelector } from "react-redux";
import { Article } from "../UI/Article";
import GenderItem from "./GenderItem";
import classes from "./GenderList.module.css";
import { genderlistActions } from "../../store/genderlist-slice";
import { useDispatch } from "react-redux";
const GenderList = () => {
const buttonDeleteHandler = useCallback( (idItem) => {
dispatch(
genderlistActions.removeItem({
id: idItem,
})
);
},[dispatch]);
const genderListItems = useSelector((state) => state.genderlist.list);
return (
<Article className={classes.article}>
<h2>History of consulted names</h2>
<ul className={classes.list}>
{genderListItems.map((item) => (
<GenderItem
key={item.id}
buttonDeleteHandler={buttonDeleteHandler}
text={item.text}
id={item.id}
/>
))}
</ul>
</Article>
);
};
export default GenderList;
It is important to pay attention to the function “buttonDeleteHandler”, which now uses the “useCallBack” hook, and this allows us to tell react that we need to save it in memory, when the component is reloaded React use the same store function. This means that the child components, those in the history list, never change because they refer to the same function.
Now we can test our application:
And deleting items:
As shown in the images, we memorized the delete function and this ensured that our items did not change and that React.memo worked correctly.
Leave a Reply