Whenever a state is updated in a React component, a re-rendering is done.
This means when we update many states, then there will be lots of re-rendering done.
In this article, we’ll look at how to reduce the number of re-renders in our React components.
How to Reduce the Number of Re-renderings?
We can reduce the number of re-renderings done by reducing the number of states that are updated.
For instance, we can update one object instead state instead of multiple states.
To do this, we write:
import { useEffect, useState } from "react";
export default function App() {
const [request, setRequest] = useState({
loading: false,
data: undefined
});
const getData = async () => {
setRequest((request) => ({ ...request, loading: true }));
const res = await fetch("https://yesno.wtf/api/");
const data = await res.json();
setRequest((request) => ({ ...request, data }));
};
useEffect(() => {
getData();
}, []);
useEffect(() => {
if (request.data) {
setRequest((request) => ({ ...request, loading: false }));
}
}, [request]);
return <div className="App">{JSON.stringify(request)}</div>;
}
We have the request
state which has the loading
and data
properties.
In the getData
function, we call setRequest
to update the request
state object’s loading
property by passing in a callback and returning a new object that’s a copy of request
, but loading
is set to true
.
At the end of the function, we call setRequest
again with the new value of data
.
Also, we have a useEffect
callback that checks is request.data
is set and call setRequest
with a callback that returns a copy of the request
object with loading
set to false
.
Another way to do this is to create our own hook to merge different state object properties together.
For instance, we can write:
import { useEffect, useState } from "react";
const useMergeState = (initialState) => {
const [state, setState] = useState(initialState);
const setMergedState = (newState) =>
setState((prevState) => ({ ...prevState, newState }));
return [state, setMergedState];
};
export default function App() {
const [request, setRequest] = useMergeState({
loading: false,
data: undefined
});
const getData = async () => {
setRequest({ loading: true });
const res = await fetch("https://yesno.wtf/api/");
const data = await res.json();
setRequest({ data });
};
useEffect(() => {
getData();
}, []);
useEffect(() => {
if (request.data) {
setRequest({ loading: false });
}
}, [request, setRequest]);
return <div className="App">{JSON.stringify(request)}</div>;
}
We created the useMergeState
hook which has the setMergedState
function that calls the setState
function to merge newState
into prevState
with the callback in setState
.
Then we call useMergeState
in App
to return our state and state setter function.
Now instead of passing in a callback to the state setter function to merge the state, we just pass in the properties that we want to change to setRequest
to change the property.
In either example, we update what we need in our object all at once instead of updating multiple primitive values.
Conclusion
We can reduce the number of re-renders to components with React and JavaScript by putting states into objects and updating them all at once.