As a core developer, when you construct an application, you consider not just how beautiful the user interface is, but also how smoothly it runs, how quickly it loads, and how fast it is. To accomplish this, we need a memoization technique.
React has two essential hooks: usecallback and usememo. Both hooks are used for function optimization and return memoized result. They both are useful in memoization but it can be difficult to determine which hook is more suitable to which condition because typically they give you similar solutions on different values.
In this tutorial, I'll clarify any confusion so you can confidently use them in your project.
Let's see the example:
Find Factors of numbers
Let's suppose we've a Factorial Calculator to find out factors of numbers. A factor is a number that divides with no remainder.
import styles from './Factoring.module.css'
import Button from './Button'
import { useState } from 'react'
const Factoring = () => {
const [number, setNumber] = useState(0)
let factors = []
for (let i=1; i<=number; i++) {
if (number % i === 0) {
factors = [...factors, i]
}
}
const factorChange = (event) => {
setNumber(parseInt(event.target.value))
}
const handleClearInput = () => {
setNumber(0)
}
return (
<div className={styles.factoring}>
<div className={styles["factoring-calct"]}>
<h1>Factoring Calculator</h1>
<p>Find the Factors of:</p>
<div>
<input type="number" value={number} onChange={factorChange} />
<Button className={styles.clearInput} label="Clear" onClick={handleClearInput} />
</div>
<div>
<h3>Factors of {number}</h3>
<span>Answer: {factors.join(', ')}</span>
</div>
</div>
</div>
)
}
export default Factoring
- I used state to manage factors where number is a user-specified value.
- Using a for loop to calculate factors that iterate from 1 to specified number.
- A function to reset number state,
- We render a number input and a Button child component to clear Input.
Following are reusable Button Component:
import { memo } from "react"
const Button = memo(({label, ...props}) => {
console.log('Button is child component')
return (
<button {...props}>{label}</button>
)
})
export default Button
In this Button component I used memo function to prevent unnecessary re-rendering of child component.
If factorial calculator solve a large numbers of calculation to find factors then the whole component will pause until it is done but sometimes we don't need to perform this calculation.
Let's suppose I'm running a countdown inside the component, and we have a state to update the countdown number every second, this would cause a performance problem because the component would repeatedly render, rerun expensive calculations, and recreate functions upon each state update.
It will also force the Button component to re-render every second, even though we are using the memo function. Becuase we are passing function onClick={handleClearInput} to the child component, memo function won't work. If you're curious about why check out useCallback complete guide.
Skip Calculations: useMemo vs useCallback
React provides various ways to implement memoization. It is particularly useful when dealing with computationally expensive or frequently called functions
The question is: which one? Let's see one by one.
useMemo
The useMemo memoizes values. The useMemo hook is very handy for expensive computations. When you declare time-consuming functions and perform complex operations like huge data filtering or sorting algorithms, you can use useMemo hook to memoize the result.
const factorize = useMemo(() => {
let factors = []
for (let i=1; i<=number; i++) {
if (number % i === 0) {
factors = [...factors, i]
}
}
return factors
}, [number])
<span>Answer: {factorize.join(', ')}</span>
If its inputs are the same as its dependencies have not changed, useMemo hook returns cached results.
useCallback
The useCallback memoizes the callback functions themselves. usecallback works exceptionally well with event handlers, especially when dealing with child components.
It creates a function reference and then on each render it returns the same function reference as long as its dependencies have not changed.
const handleClearInput = useCallback(() => {
setNumber(0)
}, [])
Impact on re-rendering
- useMemo does not directly control component re-render itself, it plays a crucial role in optimizing specific parts by memoizing the results.
- usecallback simply ensures that the child component does not re-render unnecessarily due to changes in the parent component's state.
Key use cases:
- useMemo is most effective for expensive computation within the component. It essentially caches the output of a function to avoid redundant calculations if the dependencies haven't changed.
- usecallback can be particularly beneficial when dealing with child components. It optimizes event handlers passed but does not affect the logic.
Conclusion
React checks referential equality for both, although useMemo is used for values and useCallback is given for functions.
useMemo can be used to memoize the output of a computation or to prevent the re-calculation. On the other side, you can use useCallback to avoid function re-creation.
0 Comments:
Post a Comment