⚙️ memo()
, ⚙️ useMemo()
, 🧩️ Clever Structuring 🧩️ and one optimization compiler called ⚡️MillionJS⚡️
memo()
is a utility provided by React that helps prevent unnecessary re-renders of a component when its props remain unchanged.
const IconButton = memo(function IconButton({ children, icon, ...props }) {
...
});
export default IconButton;
In the example above, memo()
takes a component function as an argument and memoizes it. When a parent component re-renders, the memoized component won't re-render unless its props change.
- children ➡️ This is static and does not change.
- icon ➡️ This is an external SVG component, always the same.
- ...props ➡️ Includes an onClick handler that could change on every render due to function recreation.
To address unnecessary re-renders caused by recreated functions, you can wrap the function in useCallback():
const handleDecrement = useCallback(function handleDecrement() { ... }, []);
With this approach, memo()
is used effectively.
Note
It's common practice to wrap functions passed as props in useCallback() when using memo()
or useEffect()
Sometimes it can be normal to want to wrap all our components in a memo()
but that will be unproductive and highly inadvisable since memo only needs to be used in a key component that groups a few or a group of components that do not need to be re-rendered. We can handle all that behavior in a common component with memo()
if we think it is the better approach.
const Counter = memo(function Counter({ initialCount }) {
...some components
}
export default Counter;
This Counter component in my React app will always be modified by that property, since the counter property is always changing because that's the behavior I want in my app.
The use of memo()
here is a bit pointless because there are no useful cases to avoid re-rendering.
In this case a better approach will be a clever structure
//CODE WITH MEMO
function App() {
log('<App /> rendered');
const [enteredNumber, setEnteredNumber] = useState(0);
const [chosenCount, setChosenCount] = useState(0);
function handleChange(event) {
setEnteredNumber(+event.target.value);
}
function handleSetClick() {
setChosenCount(enteredNumber);
setEnteredNumber(0);
}
return (
<>
...
<section id="configure-counter">
<h2>Set Counter</h2>
<input type="number" onChange={handleChange} value={enteredNumber} />
<button onClick={handleSetClick}>Set</button>
</section>
<Counter initialCount={chosenCount} /> //Notice that this component is being re-rendered caused that chosenCount prop is changing frequently caused by some state
...
</>
//CODE WITH CLEVER STRUCTURING
function App() {
log("<App /> rendered");
const [chosenCount, setChosenCount] = useState(0);
function handleSetCount(newCount) {
setChosenCount(newCount);
}
return (
<>
<Header />
<main>
<ConfigureCounter onSet={handleSetCount} /> //Now all that state behaviour are in a separate component.
<Counter initialCount={chosenCount} /> //Counter now only re-renders when its props actually change.
</main>
</>
It is very common to have some complex and long functions that consume some computational time, so re-executing that function every time a component is re-rendered could lead to a performance downgrade.
const initialCountIsPrime = useMemo(
() => isPrime(initialCount),
[initialCount]
);
useMemo()
needs a function that should return the computed value we want to memoize and an array of dependencies (deps) to re-execute that function only when its dependencies change.
Million.js replace React's virtual DOM with a faster, lightweight virtual DOM, enabling more efficient updates and reducing rendering overhead.
npx million@latest
On installation, you'll be prompted to install the Million Lint build plugin and VSCode extension. That's it! You're all set up 🎉
That's all for this project, in conclusion:
memo()
➡️ try to memoize a common component and keep an eye on the properties to avoid unnecessary renderings like function recreations (useCallback()) or frequently state changes (Clever Structuring)useMemo()
➡️ memoize the computed value of a long and complex function that can take some time and only re-execute when a dependency changes.- Clever Structuring ➡️ Allow me to make more agile and readable code by taking advantage of React's way of thinking and avoiding unnecessary hooks.
🐸 This project is a practice exercise I learned from the Academind's React Course 🐸