React: Performance Hooks
Created on: Sep 18, 2024
Performance hooks are a way to skip the unnecessary work and optimize the rendering performance.
1. useMemo
useMemo hook is used to get the memoized value of a function in react components.
import React, { useState, useMemo } from "react"; function Square() { const [number, setNumber] = useState(0); const squaredNum = useMemo(() => { return squareNum(number); }, [number]); const [counter, setCounter] = useState(0); const onChangeHandler = (e) => { setNumber(e.target.value); }; const counterHander = () => { setCounter(counter + 1); }; return ( <div className="App"> <h1>Welcome to Geeksforgeeks</h1> <input type="number" placeholder="Enter a number" value={number} onChange={onChangeHandler} ></input> <div>OUTPUT: {squaredNum}</div> <button onClick={counterHander}>Counter ++</button> <div>Counter : {counter}</div> </div> ); } function squareNum(number) { console.log("Squaring will be done!"); return Math.pow(number, 2); } export default Square;
2. useCallback:
useCallback is a React Hook that lets you cache a function definition between re-renders.
Let's consider a example to understand this.
import React, { useState } from "react"; const funccount = new Set(); const Counter = () => { const [count, setCount] = useState(0); const [number, setNumber] = useState(0); const incrementCounter = () => { setCount(count + 1); }; const decrementCounter = () => { setCount(count - 1); }; const incrementNumber = () => { setNumber(number + 1); }; funccount.add(incrementCounter); funccount.add(decrementCounter); funccount.add(incrementNumber); alert(funccount.size); return ( <div> Count: {count} <button onClick={incrementCounter}>Increase counter</button> <button onClick={decrementCounter}>Decrease Counter</button> <button onClick={incrementNumber}>increase number</button> </div> ); }; export default Counter;
The problem is that once the counter is updated, all three functions are recreated again. The alert increases by three at a time but if we update some states all the functions related to that states should only re-instantiated. If another state value is unchanged, it should not be touched.
To solve this problem we can use the useCallback hook.
import React, { useState, useCallback } from "react"; const funccount = new Set(); const Counter = () => { const [count, setCount] = useState(0); const [number, setNumber] = useState(0); const incrementCounter = useCallback(() => { setCount(count + 1); }, [count]); const decrementCounter = useCallback(() => { setCount(count - 1); }, [count]); const incrementNumber = useCallback(() => { setNumber(number + 1); }, [number]); funccount.add(incrementCounter); funccount.add(decrementCounter); funccount.add(incrementNumber); alert(funccount.size); return ( <div> Count: {count} <button onClick={incrementCounter}>Increase counter</button> <button onClick={decrementCounter}>Decrease Counter</button> <button onClick={incrementNumber}>increase number</button> </div> ); }; export default Counter;
3. useTransition:
useTransition is a React Hook that lets you update the state without blocking the UI.
In below code, our list is so big, looping over it 10000 times, and saving each value we type, and rendering it all on the screen takes a long time and will be very slow to process. This is a problem since the list state update occurs concurrently with the name state update, thus the component will not redraw with the new state values for either piece of state until both have completed processing
import React, { useState } from "react"; function WithoutTrans() { const [name, setName] = useState(""); const [lists, setLists] = useState([]); const LIST_SIZE = 10000; const handleChange = (e) => { const { value } = e.target; setName(value); const dataList = []; for (let i = 0; i < LIST_SIZE; i++) { dataList.push(value); } setLists(dataList); }; return ( <div> <input type="text" value={name} onChange={handleChange} /> {lists.map((list) => { return <div key={list}>{list}</div>; })} </div> ); } export default WithoutTrans;
The useTransition hook enables us to mark some state modifications as unimportant.These state updates will be performed in parallel with other state updates, but the rendering of the component will not be delayed.
import React, { useState, useTransition } from "react"; function Trans() { const [name, setName] = useState(""); const [lists, setLists] = useState([]); const [isPending, startTransition] = useTransition(); const LIST_SIZE = 10000; const handleChange = (e) => { const { value } = e.target; setName(value); startTransition(() => { const dataList = []; for (let i = 0; i < LIST_SIZE; i++) { dataList.push(value); } setLists(dataList); }); }; return ( <div> <input type="text" value={name} onChange={handleChange} /> {isPending ? ( <div>Loading...</div> ) : ( lists.map((list) => { return <div key={list}>{list}</div>; }) )} </div> ); } export default Trans;
For more details check medium
4. useDeferredValue:
useDeferredValue is a React Hook that lets you defer updating a part of the UI.
import React, { useState, useDeferredValue } from "react"; const DefferedComponent = () => { const [count, setCount] = useState(0); const deferredCount = useDeferredValue(count, { timeoutMs: 1000, }); const handleClick = () => { setCount(count + 1); }; return ( <div> <h1>Counter</h1> <p>Current count: {count}</p> <button onClick={handleClick}>Click me</button> <p>Deferred count: {deferredCount}</p> </div> ); }; export default DefferedComponent;
In above example, the count state variable is updated immediately when the user clicks the button. However, the deferredCount value is not updated immediately. Instead, it is updated after 1000 milliseconds. This means that the deferredCount value will not reflect the latest value of the count state variable until after 1000 milliseconds have passed.
Below are example where we can use this hook.
- Image Loading: Suppose you’re building an image-heavy application where you need to display a list of images fetched from an API. Instead of loading all images immediately, you can defer loading images that are not currently visible on the screen using useDeferredValue. This prevents unnecessary network requests and improves the initial rendering performance.
- Autocomplete Search: In an autocomplete search feature, you might want to delay the search query until the user has stopped typing for a short duration. useDeferredValue can help achieve this by deferring the update of the search query until the user stops typing, reducing the number of unnecessary API calls.
You can find full code in my github
Links of all hooks
Reference
- https://medium.com/@ahsan-ali-mansoor/usetransition-hook-explained-885e87414b8
- https://medium.com/@mujaffarhssn/the-usedeferredvalue-hook-a-simple-way-to-improve-performance-7f457600cab6
- https://medium.com/zestgeek/understanding-reacts-usedeferredvalue-hook-a-comprehensive-guide-with-examples-f8aa3361ee23