How to avoid un-necessary re-renders in react component
React has come long way from its early stages. Still many of us find it difficult to fix the un-necessary re-renders.
There are many approaches out there to avoid re-renders. Here I am discussing some of the methods and approaches to avoid un-necessary re-renders in React.
Replacing useState()with useRef()hook.
Using Reselect library to create Memoized selectors
Using SWR a React Hooks library for data fetching.
Memoization using useMemo() and useCallback()Hooks.
*1. Replacing useState() with useRef() hook.
*
useState() is hook is commonly used hook in React functional components to re-render the component on state changes. But in some cases we need to track the update without re-rendering the component. To solve this we can use useRef() hook, when we use useRef() for the updates it will not fire re-rendering unlike useState()
Example with useState():
function inputWithState() {
const [value, setValue] = useState("");
return (
<input
value={value}
onChange={e => setValue(e.target.value)}
type={type}
/>
);
}
In this example every key stroke in input will re-render because of state change with onChange event.
Example with useRef():
function inputWithRef() {
const inputEl = useRef(null);
console.log(inputEl?.current?.value);
return (
<input ref={inputEl} type="text" />
);
}
In this example what ever you type in input you can read that using input reference. This approach avoid un-necessary re-rendering on each keystroke.
2. Using Reselect library to create Memoized selectors
React components have a fast lifecycle, they always suffer due to so much re-rendering, causing production time and performance. To fight this, developers created a third-party performance library re-select, a wrapper for the popular library Reselect, which is used with Redux to improve the performance by coding memoized selectors.
Selectors can compute derived data, allowing Redux to store the minimal possible state.
Selectors are efficient. A selector is not recomputed unless one of its arguments changes.
Selectors are composable. They can be used as input to other selectors.
Example:
import { createSelector } from 'reselect'
const selectShopItems = state => state.shop.items
const selectTaxPercent = state => state.shop.taxPercent
const selectSubtotal = createSelector(selectShopItems, items =>
items.reduce((subtotal, item) => subtotal + item.value, 0)
)
const selectTax = createSelector(
selectSubtotal,
selectTaxPercent,
(subtotal, taxPercent) => subtotal * (taxPercent / 100)
)
const selectTotal = createSelector(
selectSubtotal,
selectTax,
(subtotal, tax) => ({ total: subtotal + tax })
)
const exampleState = {
shop: {
taxPercent: 8,
items: [
{ name: 'apple', value: 1.2 },
{ name: 'orange', value: 0.95 }
]
}
}
console.log(selectSubtotal(exampleState)) // 2.15
console.log(selectTax(exampleState)) // 0.172
console.log(selectTotal(exampleState)) // { total: 2.322 }
Here, the createSelector takes 2 selectors as the input and returns the memoized version. Selectors will not be re-computed again with this memoized version until the values are different.
While Reselect is not exclusive to Redux, it is already included by default in the official Redux Toolkit package โ no further installation needed.
3. Using SWR a React Hooks library for data fetching
SWR is a React Hooks library for data fetching.
The name โSWRโ is derived from stale-while-revalidate. SWR first returns the data from cache (stale), then sends the request (revalidate), and finally comes with the up-to-date data again. it will prevent the component from re-rendering multiple times.
With just one hook, you can significantly simplify the data fetching logic in your project. And it also covered in all aspects of speed, correctness, and stability to help you build better.
Example:
function Profile() {
const { data, error } = useSWR('/api/user', fetcher)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
Refer here for more info and examples: https://swr.vercel.app/
4. Memoization using useMemo() and useCallback()Hooks
Memoization enables our react code to re-render components only if there is an update in the props. With this approach, developers can avoid unnecessary re-renderings and reduce the computational load in applications.
React provides two Hooks to create memoization:
useMemo()
useCallback()
These Hooks reduce re-renderings by caching and returning the same output if the inputs are the same without any computations. When the inputs updates, the cache gets invalidated and the new component state gets rendered.
useMemo()
This hook is used to memoize a calculation result between a functionโs calls and between renders.
Example:
const expensiveFunction = (inputValue) => {
let expensiveValue = inputValue * 42;
//... lots and lots of computing including inputValue ...
expensiveValue = 'World';
return expensiveValue;
};
const MyComponent = ({ something }) => {
const [inputValue, setInputValue] = useState('');
const expensiveValue = useMemo(
() => expensiveFunction(inputValue),
[ inputValue ]
);
return <h1>Hello {expensiveValue}</h1>;
};
2. useCallback()
This is another React Hook to implement memoization. But, unlike useMemo(), it does not cache the result. Instead, it memoizes the callback function provided to it.
Example:
function item() {
const onClick = useCallback(event => {
console.log('Clicked Item : ', event.currentTarget);
}, [item]);
return (
<li={item} onClick={onClick} />
);
}
In example, useCallBack() memoizes the onClick callback. So, it will not re-render the component if the user clicks the same item again and again.
Hope this article help developers to solve re-rendering issues in React Components. Please help to learn if you have any other approach or techniques to avoid re-rendering in React please add it in the comments.
Thanks for the read. Cheers!!!.
You are Awesome !
Top comments (0)