Boost Your React Components: A Beginner's Guide to React.memo, useMemo, and useCallback
Tags: react, webdev, javascript
Published: 2024-01-28 16:03:16

Welcome, fellow React enthusiasts! If you've ever wondered how to supercharge your React components for a optimized user experience, you're in the right place. In this blog, we'll embark on a beginner-friendly journey through three fantastic techniques: `React.memo`, `useMemo`, and `useCallback`. These tricks may sound fancy, but fear not - we'll break them down into bite-sized, easy-to-digest nuggets.

1. `React.memo` - Higher order component

In regular React behavior, when a parent component updates, it usually causes its child components to also update or re-render. However, with the use of `memo`, you can make a component that won't re-render when its parent updates, as long as the new information it gets (props) is the same as what it had before. This kind of component is called "memoized."

To memoize a component, you can simply wrap it with the `memo` function. Then, instead of using your original component directly, you use the value returned by the memo. This helps optimize performance by preventing unnecessary re-renders when the component's props haven't changed.

```
import React, { useState } from "react";

export const ReactMemoExample = () => {
  const [value, setValue] = useState(0);
  const [anotherValue, setAnotherValue] = useState(1);
  console.log("Parent component is render");
  return (
    <div>
      <h3>React.Memo example</h3>
      <button onClick={() => setAnotherValue(anotherValue + 1)}>
        Change Parent state
      </button>
     <button onClick={() => setValue(value + 1)}>
        Change Prop passed to child
     </button>
      <MemoizedComponent value={value}></MemoizedComponent>
      <NonMemoizedComponent value={value}></NonMemoizedComponent>
    </div>
  );
};
const MemoizedComponent = React.memo(({ value }) => {
  console.log("Memoized child component is rendered");
  return <> Value: {value}</>;
});
const NonMemoizedComponent = ({ value }) => {
  console.log("NonMemoizedComponent Child component is rendered");
  return <> Value: {value}</>;
};
```
In the example provided, take a look at the logs for both components, one with memoization and the other without. 
The memoized component remains unchanged unless its prop value is altered. When you click the button labeled as `Change Parent state` the memoized component doesn't undergo a re-render, whereas the non-memoized component is needlessly rendered.

2. `useMemo` hook

If you want to remember or save the result of a calculation in a React component and avoid recalculating it every time the component renders, you can use `useMemo`.
In simple terms, `useMemo` acts like a memory bank for your calculations. It keeps the calculated result safe and only recomputes it if something in your component has changed. This helps optimize your component's performance by avoiding unnecessary recalculations.

```
import React, { useMemo, useState } from "react";

export const UseMemoExample = () => {
  const [users] = useState([
    { name: "John", active: true },
    { name: "Mike", active: false },
  ]);
  const [someState, setSomeState] = useState(0);
  console.log("UseMemoExample Component Rendered");
  return (
    <div>
      <h3>useMemo example</h3>
      <button onClick={() => setSomeState(someState + 1)}>
        Change Parent State
      </button>
      <ComponentUsingMemo users={users}></ComponentUsingMemo>
    </div>
  );
};

function ComponentUsingMemo({ users }) {
  console.log("ComponentUsingMemo is rendered")
  const activeUsers = useMemo(() => {
    console.log("Filtering users.")
    return users.filter((user) => user.active)
  }, [users]);
  return <div>User count {activeUsers.length}</div>;
}

function ComponentWithoutMemo({ users }) {
  console.log("ComponentWithoutMemo is rendered")
  const activeUsers = users.filter((user) => user.active)
  return <div>User count {activeUsers.length}</div>;
}
```

In the example above, notice how many times "Filtering users." shows up in the console. Even if the child component is displayed, the math is only done when the list of users changes.
Think of `useMemo` like a helper that remembers how to do a specific calculation. It needs two things: the math it should do and a list of things to pay attention to (we call this the dependencies list).
So, the calculation only happens again when the stuff in the dependencies list changes.

3. `useCallback` hook

It is a Hook in React that is used to memoize functions. It returns a memoized version of the callback function that only changes if one of the dependencies has changed. This is particularly useful when passing callbacks to child components, as it can prevent unnecessary re-renders when the parent component re-renders.

Example:
```
import React, { useState, useCallback } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  // Memoized increment function
  const increment = useCallback(() => {
    setCount((prevCount) => prevCount + 1);
  }, []); // No dependencies, so always the same function reference

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};

export default Counter;
```

In the example above, the increment function is set up just once. This avoids unnecessary reinitialization when the component's state changes.