How to write performant React code: rules, patterns, do's and don'ts
Tags: react, performance, webdev, javascript
Published: 2022-01-10 11:27:53


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tr0t9ogsikrkl2rqgr3p.jpg)


Originally published at [https://www.developerway.com](https://www.developerway.com). The website has more articles like this 😉

---

Performance and React! Such a fun topic with so many controversial opinions and so many best practices flipping to be the opposite in just 6 months. Is it even possible to say anything definitive here or to make any generalized recommendations?

Usually, performance experts are the proponents of “premature optimisation is the root of all evil” and “measure first” rules. Which loosely translates into “don’t fix that is not broken” and is quite hard to argue with. But I’m going to anyway 😉

What I like about React, is that it makes implementing complicated UI interactions incredibly easy. What I don’t like about React, is that it also makes it incredibly easy to make mistakes with huge consequences that are not visible right away. The good news is, it’s also incredibly easy to prevent those mistakes and write code that is performant most of the time right away, thus significantly reducing the time and effort it takes to investigate performance problems since there will be much fewer of those. Basically, “premature optimisation”, when it comes to React and performance, can actually be a good thing and something that everyone should do 😉. You just need to know a few patterns to watch out for in order to do that meaningfully.

So this is exactly what I want to prove in this article 😊. I’m going to do that by implementing a “real-life” app step by step, first in a “normal” way, using the patterns that you’ll see practically everywhere and surely used multiple times by yourself. And then refactor each step with performance in mind, and extract a generalized rule from every step that can be applied to most apps most of the time. And then compare the result in the end.

Let’s begin!

We are going to write one of the “settings” page for an online shop (that we introduced into the previous “Advanced typescript for React developers” articles). On this page, users will be able to select a country from the list, see all the information available for this country (like currency, delivery methods, etc), and then save this country as their country of choice. The page would look something like this:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8mjrlrsd6ru0hawgdiwr.png)


On the left we’ll have a list of countries, with “saved” and “selected” states, when an item in the list is clicked, in the column on the right the detailed information is shown. When the “save” button is pressed, the “selected” country becomes “saved”, with the different item colour.

Oh, and we’d want the dark mode there of course, it’s 2022 after all!

Also, considering that in 90% of the cases performance problems in React can be summarised as “too many re-renders”, we are going to focus mostly on reducing those in the article. (Another 10% are: “renders are too heavy” and “really weird stuff that need further investigation”.)

## Let's structure our app first

First of all, let's take a look at the design, draw imaginary boundaries, and draft the structure of our future app and which components we’d need to implement there:

- a root “Page” component, where we’d handle the “submit” logic and country selection logic
- a “List of countries” component, that would render all the countries in a list, and in the future handle things like filtering and sorting
- “Item” component, that renders the country in the “List of countries”
- a “Selected country” component, that renders detailed information about the selected country and has the “Save” button


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5hgwpox2cfo73rad3059.png)


This is, of course, not the only possible way to implement this page, that’s the beauty and the curse of React: everything can be implemented in a million ways and there is no right or wrong answer for anything. But there are some patterns that in the long run in fast-growing or large already apps can definitely be called **“never do this”** or **“this is a must-have”**.

Let’s see whether we can figure them out together 🙂


## Implementing Page component

Now, finally, the time to get our hands dirty and do some coding. Let’s start from the “root” and implement the Page component.

First: we need a wrapper with some styles that renders page title, “List of countries” and “Selected country” components.

Second: out page should receive the list of countries from somewhere, and then pass it to the `CountriesList` component so that it could render those.

Third: our page should have an idea of a “selected” country, that will be received from the `CountriesList` component and passed to the `SelectedCountry` component.

And finally: our page should have an idea of a “saved” country, that will be received from the `SelectedCountry` component and passed to the `CountriesList` component (and be sent to the backend in the future).

```tsx
export const Page = ({ countries }: { countries: Country[] }) => {
  const [selectedCountry, setSelectedCountry] = useState<Country>(countries[0]);
  const [savedCountry, setSavedCountry] = useState<Country>(countries[0]);

  return (
    <>
      <h1>Country settings</h1>
      <div css={contentCss}>
        <CountriesList
          countries={countries}
          onCountryChanged={(c) => setSelectedCountry(c)}
          savedCountry={savedCountry}
        />
        <SelectedCountry
          country={selectedCountry}
          onCountrySaved={() => setSavedCountry(selectedCountry)}
        />
      </div>
    </>
  );
};
```

That is the entire implementation of the “Page” component, it’s the most basic React that you can see everywhere, and there is absolutely nothing criminal in this implementation. Except for one thing. Curious, can you see it?

### Refactoring Page component - with performance in mind

I think it is common knowledge by now, that react re-renders components when there is a state or props change. In our Page component when `setSelectedCountry` or `setSavedCountry` is called, it will re-render. If the countries array (props) in our Page component changes, it will re-render. And the same goes for `CountriesList` and `SelectedCountry` components - when any of their props change, they will re-render.

Also, anyone, who spent some time with React, knows about javascript <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness">equality comparison</a>, the fact that React does strict equality comparison for props, and the fact that inline functions create new value every time. This leads to the very common (and absolutely wrong btw) belief, that in order to reduce re-renders of `CountriesList` and `SelectedCountry` components we need to get rid of re-creating inline functions on every render by wrapping inline functions in `useCallback`. Even <a href="https://reactjs.org/docs/hooks-reference.html#usecallback">React docs</a> mention `useCallback` in the same sentence with “prevent unnecessary renders”! See whether this pattern looks familiar:

```tsx
export const Page = ({ countries }: { countries: Country[] }) => {
  // ... same as before

  const onCountryChanged = useCallback((c) => setSelectedCountry(c), []);
  const onCountrySaved = useCallback(() => setSavedCountry(selectedCountry), []);

  return (
    <>
      ...
        <CountriesList
          onCountryChanged={onCountryChange}
        />
        <SelectedCountry
          onCountrySaved={onCountrySaved}
        />
      ...
    </>
  );
};
```

Do you know the funniest part about it? It actually **doesn’t work**. Because it doesn’t take into account the third reason why React components are re-rendered: **when the parent component is re-rendered**. Regardless of the props, `CountriesList` will always re-render if Page is re-rendered, even if it doesn’t have any props at all.

We can simplify the Page example into just this:

```tsx
const CountriesList = () => {
  console.log("Re-render!!!!!");
  return <div>countries list, always re-renders</div>;
};

export const Page = ({ countries }: { countries: Country[] }) => {
  const [counter, setCounter] = useState<number>(1);

  return (
    <>
      <h1>Country settings</h1>
      <button onClick={() => setCounter(counter + 1)}>
        Click here to re-render Countries list (open the console) {counter}
      </button>
      <CountriesList />
    </>
  );
};
```

And every time we click the button, we’ll see that `CountriesList` is re-rendered, **even if it doesn’t have any props at all**. <a href="https://codesandbox.io/s/re-renders-simplified-bad-1giei?file=/src/country-settings/page.tsx">Codesandbox code is here</a>.

And this, finally, allows us to solidify the very first rule of this article:

> <b>Rule #1.</b> If the only reason you want to extract your inline functions in props into useCallback is to avoid re-renders of children
  components: don’t. It doesn’t work.

Now, there are <a href="https://overreacted.io/before-you-memo/">a few ways</a> to deal with situations like the above, I am going to use the simplest one for this particular occasion: <a href="https://reactjs.org/docs/hooks-reference.html#usememo">useMemo</a> hook. What it does is it’s essentially “caches” the results of whatever function you pass into it, and only refreshes them when a _dependency_ of `useMemo` is changed. If I just extract the rendered `CountriesList` into a variable `const list = <ComponentList />;` and then apply `useMemo` on it, the `ComponentList` component now will be re-rendered **only when useMemo dependencies will change**.

```tsx
export const Page = ({ countries }: { countries: Country[] }) => {
  const [counter, setCounter] = useState<number>(1);

  const list = useMemo(() => {
    return <CountriesList />;
  }, []);

  return (
    <>
      <h1>Country settings</h1>
      <button onClick={() => setCounter(counter + 1)}>
        Click here to re-render Countries list (open the console) {counter}
      </button>
      {list}
    </>
  );
};
```

Which in this case is never, since it doesn’t have any dependencies. This pattern basically allows me to break out of this “parent re-renders - re-render all the children regardless” loop and take control over it. Check out the <a href="https://codesandbox.io/s/re-renders-simplified-memo-xcv5f?file=/src/country-settings/page.tsx">full example in codesandbox</a>.

The most important thing there to be mindful of is the list of dependencies of `useMemo`. If it depends on exactly the same thing that causes the parent component to re-render, then it’s going to refresh its cache with every re-render, and essentially becomes useless. For example, if in this simplified example I pass the `counter` value as a dependency to the `list` variable (notice: not even a prop to the memoised component!), that will cause `useMemo` to refresh itself with every state change and will make `CountriesList` re-render again.

```tsx
const list = useMemo(() => {
  return (
    <>
      {counter}
      <CountriesList />
    </>
  );
}, [counter]);
```

<a href="https://codesandbox.io/s/re-renders-simplified-memo-with-dep-9h433?file=/src/country-settings/page.tsx:363-491">
  See the codesandbox example.
</a>

Okay, so all of this is great, but how exactly it can be applied to our non-simplified Page component? Well, if we look closely to its implementation again

```tsx
export const Page = ({ countries }: { countries: Country[] }) => {
  const [selectedCountry, setSelectedCountry] = useState<Country>(countries[0]);
  const [savedCountry, setSavedCountry] = useState<Country>(countries[0]);

  return (
    <>
      <h1>Country settings</h1>
      <div css={contentCss}>
        <CountriesList
          countries={countries}
          onCountryChanged={(c) => setSelectedCountry(c)}
          savedCountry={savedCountry}
        />
        <SelectedCountry
          country={selectedCountry}
          onCountrySaved={() => setSavedCountry(selectedCountry)}
        />
      </div>
    </>
  );
};
```

we’ll see that:

- `selectedCountry` state is never used in `CountriesList` component
- `savedCountry` state is never used in `SelectedCountry` component


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r172i5nksygdf3zpukzb.png)


Which means that when `selectedCountry` state changes, `CountriesList` component doesn’t need to re-render at all! And the same story with `savedCountry` state and `SelectedCountry` component. And I can just extract both of them to variables and memoise them to prevent their unnecessary re-renders:

```tsx
export const Page = ({ countries }: { countries: Country[] }) => {
  const [selectedCountry, setSelectedCountry] = useState<Country>(countries[0]);
  const [savedCountry, setSavedCountry] = useState<Country>(countries[0]);

  const list = useMemo(() => {
    return (
      <CountriesList
        countries={countries}
        onCountryChanged={(c) => setSelectedCountry(c)}
        savedCountry={savedCountry}
      />
    );
  }, [savedCountry, countries]);

  const selected = useMemo(() => {
    return (
      <SelectedCountry
        country={selectedCountry}
        onCountrySaved={() => setSavedCountry(selectedCountry)}
      />
    );
  }, [selectedCountry]);

  return (
    <>
      <h1>Country settings</h1>
      <div css={contentCss}>
        {list}
        {selected}
      </div>
    </>
  );
};
```

And this, finally, lets us formalize the second rule of this article:

> <b>Rule #2</b>. If your component manages state, find parts of the render tree that don’t depend on the changed state and memoise them to
  minimize their re-renders.


## Implementing the list of countries

Now, that our Page component is ready and perfect, time to flesh out its children. First, let’s implement the complicated component: `CountriesList`. We already know, that this component should accept the list of countries, should trigger `onCountryChanged` callback when a country is selected in the list, and should highlight the `savedCountry` into a different color, according to design. So let’s start with the simplest approach:

```tsx
type CountriesListProps = {
  countries: Country[];
  onCountryChanged: (country: Country) => void;
  savedCountry: Country;
};

export const CountriesList = ({
  countries,
  onCountryChanged,
  savedCountry
}: CountriesListProps) => {
  const Item = ({ country }: { country: Country }) => {
    // different className based on whether this item is "saved" or not
    const className = savedCountry.id === country.id ? "country-item saved" : "country-item";

    // when the item is clicked - trigger the callback from props with the correct country in the arguments
    const onItemClick = () => onCountryChanged(country);
    return (
      <button className={className} onClick={onItemClick}>
        <img src={country.flagUrl} />
        <span>{country.name}</span>
      </button>
    );
  };

  return (
    <div>
      {countries.map((country) => (
        <Item country={country} key={country.id} />
      ))}
    </div>
  );
};
```

Again, the simplest component ever, only 2 things are happening there, really:

- we generate the `Item` based on the props we receive (it depends on both `onCountryChanged` and `savedCountry`)
- we render that `Item` for all countries in a loop

And again, there is nothing criminal about any of this _per se_, I have seen this pattern used pretty much everywhere.

### Refactoring List of countries component - with performance in mind

Time again to refresh a bit our knowledge of how React renders things, this time - what will happen if a component, like `Item` component from above, is created _during another component render_? Short answer - nothing good, really. From React’s perspective, this `Item` is just a function that is new on every render, and that returns a new result on every render. So what it will do, is on **every render** it will re-create results of this function from scratch, i.e. it will just compare the previous component state with the current one, like it happens during normal re-render. It will drop the previously generated component, including its DOM tree, remove it from the page, and will generate and mount a completely new component, with a completely new DOM tree every single time the parent component is re-rendered.

If we simplify the countries example to demonstrate this effect, it will be something like this:

```tsx
const CountriesList = ({ countries }: { countries: Country[] }) => {
  const Item = ({ country }: { country: Country }) => {
    useEffect(() => {
      console.log("Mounted!");
    }, []);
    console.log("Render");
    return <div>{country.name}</div>;
  };

  return (
    <>
      {countries.map((country) => (
        <Item country={country} />
      ))}
    </>
  );
};
```

This is the heaviest operation from them all in React. 10 “normal” re-renders is nothing compared to the full re-mounting of a freshly created component from a performance perspective. In normal circumstances, `useEffect` with an empty dependencies array would be triggered only once - after the component finished its mounting and very first rendering. After that the light-weight re-rendering process in React kicks in, and component is not created from scratch, but only updated when needed (that’s what makes React so fast btw). Not in this scenario though - take a look at <a href="https://codesandbox.io/s/creating-components-in-render-bad-8otem?file=/src/country-settings/page.tsx">this codesandbox</a>, click on the “re-render” button with open console, and enjoy 250 renders AND mountings happening on every click.

The fix for this is obvious and easy: we just need to move the `Item` component outside of the render function.

```tsx
const Item = ({ country }: { country: Country }) => {
  useEffect(() => {
    console.log("Mounted!");
  }, []);
  console.log("Render");
  return <div>{country.name}</div>;
};

const CountriesList = ({ countries }: { countries: Country[] }) => {
  return (
    <>
      {countries.map((country) => (
        <Item country={country} />
      ))}
    </>
  );
};
```

Now in our <a href="https://codesandbox.io/s/creating-components-in-render-fixed-cs7pe?file=/src/country-settings/page.tsx">simplified codesandbox</a> mounting doesn’t happen on every re-render of the parent component.

As a bonus, refactoring like this helps maintain healthy boundaries between different components and keep the code cleaner and more concise. This is going to be especially visible when we apply this improvement to our “real” app. Before:

```tsx
export const CountriesList = ({
  countries,
  onCountryChanged,
  savedCountry
}: CountriesListProps) => {

  // only "country" in props
  const Item = ({ country }: { country: Country }) => {
    // ... same code
  };

  return (
    <div>
      {countries.map((country) => (
        <Item country={country} key={country.id} />
      ))}
    </div>
  );
};
```

After:

```tsx
type ItemProps = {
  country: Country;
  savedCountry: Country;
  onItemClick: () => void;
};

// turned out savedCountry and onItemClick were also used
// but it was not obvious at all in the previous implementation
const Item = ({ country, savedCountry, onItemClick }: ItemProps) => {
  // ... same code
};

export const CountriesList = ({
  countries,
  onCountryChanged,
  savedCountry
}: CountriesListProps) => {
  return (
    <div>
      {countries.map((country) => (
        <Item
          country={country}
          key={country.id}
          savedCountry={savedCountry}
          onItemClick={() => onCountryChanged(country)}
        />
      ))}
    </div>
  );
};
```

Now, that we got rid of the re-mounting of `Item` component every time the parent component is re-rendered, we can extract the third rule of the article:

> <b>Rule #3</b>. Never create new components inside the render function of another component.


## Implementing selected country

Next step: the “selected country” component, which is going to be the shortest and the most boring part of the article, since there is nothing to show there really: it’s just a component that accepts a property and a callback, and renders a few strings:

```tsx
const SelectedCountry = ({ country, onSaveCountry }: { country: Country; onSaveCountry: () => void }) => {
  return (
    <>
      <ul>
        <li>Country: {country.name}</li>
        ... // whatever country's information we're going to render
      </ul>
      <button onClick={onSaveCountry} type="button">Save</button>
    </>
  );
};
```

🤷🏽‍♀️ That’s it! It’s only here just to make the demo codesandbox more interesting 🙂

## Final polish: theming

And now the final step: dark mode! Who doesn’t love those? Considering that the current theme should be available in most components, passing it through props everywhere would be a nightmare, so React Context is the natural solution here.

Creating theme context first:

```tsx
type Mode = 'light' | 'dark';
type Theme = { mode: Mode };
const ThemeContext = React.createContext<Theme>({ mode: 'light' });

const useTheme = () => {
  return useContext(ThemeContext);
};
```

Adding context provider and the button to switch it to the Page component:

```tsx
export const Page = ({ countries }: { countries: Country[] }) => {
  // same as before
  const [mode, setMode] = useState<Mode>("light");

  return (
    <ThemeContext.Provider value={{ mode }}>
      <button onClick={() => setMode(mode === 'light' ? 'dark' : 'light')}>Toggle theme</button>
      // the rest is the same as before
    </ThemeContext.Provider>
  )
}
```

And then using the context hook to color our buttons in the appropriate theme:

```tsx
const Item = ({ country }: { country: Country }) => {
    const { mode } = useTheme();
    const className = `country-item ${mode === "dark" ? "dark" : ""}`;
    // the rest is the same
}
```

Again, nothing criminal in this implementation, a very common pattern, especially for theming.

### Refactoring theming - with performance in mind.

Before we’ll be able to catch what’s wrong with the implementation above, time to look into a fourth reason why a React component can be re-rendered, that often is forgotten: <b>if a component uses context consumer, it will be re-rendered every time the context provider’s value is changed.</b>

Remember our simplified example, where we memoised the render results to avoid their re-renders?

```tsx
const Item = ({ country }: { country: Country }) => {
  console.log("render");
  return <div>{country.name}</div>;
};

const CountriesList = ({ countries }: { countries: Country[] }) => {
  return (
    <>
      {countries.map((country) => (
        <Item country={country} />
      ))}
    </>
  );
};

export const Page = ({ countries }: { countries: Country[] }) => {
  const [counter, setCounter] = useState<number>(1);

  const list = useMemo(() => <CountriesList countries={countries} />, [
    countries
  ]);

  return (
    <>
      <h1>Country settings</h1>
      <button onClick={() => setCounter(counter + 1)}>
        Click here to re-render Countries list (open the console) {counter}
      </button>
      {list}
    </>
  );
};
```

`Page` component will re-render every time we click the button since it updates the state on every click. But `CountriesList` is memoised and is independent of that state, so it won’t re-render, and as a result `Item` component won’t re-render as well. See the <a href="https://codesandbox.io/s/context-before-good-duhgf?file=/src/country-settings/page.tsx">codesandbox here</a>.

Now, what will happen if I add the Theme context here? Provider in the `Page` component:

```tsx
export const Page = ({ countries }: { countries: Country[] }) => {
  // everything else stays the same

  // memoised list is still memoised
  const list = useMemo(() => <CountriesList countries={countries} />, [
    countries
  ]);

  return (
    <ThemeContext.Provider value={{ mode }}>
      // same
    </ThemeContext.Provider>
  );
};
```

And context in the Item component:

```tsx
const Item = ({ country }: { country: Country }) => {
  const theme = useTheme();
  console.log("render");
  return <div>{country.name}</div>;
};
```

If they were just normal components and hooks, nothing would’ve happened - `Item` is not a child of `Page` component, `CountriesList` won’t re-render because of memoisation, so `Item` wouldn’t either. Except, in this case, it’s a Provider-consumer combination, so every time the value on the provider changes, **all** of the consumers will re-render. And since we’re passing new object to the value all the time, _`Items` will unnecessary re-render on every counter_. Context basically bypasses the memorisation we did and makes it pretty much useless. <a href="https://codesandbox.io/s/context-bad-4zou7?file=/src/country-settings/page.tsx">See the codesandbox.</a>

The fix to it, as you might have already guessed, is just to make sure that the `value` in the provider doesn’t change more than it needs to. In our case, we just need to memoise it as well:

```tsx
export const Page = ({ countries }: { countries: Country[] }) => {
  // everything else stays the same

  // memoising the object!
  const theme = useMemo(() => ({ mode }), [mode]);

  return (
    <ThemeContext.Provider value={theme}>
      // same
    </ThemeContext.Provider>
  );
};
```

And now the counter will work without causing all the Items to re-render!

And absolutely the same solution for preventing unnecessary re-renders we can apply to our non-simplified `Page` component:

```tsx
export const Page = ({ countries }: { countries: Country[] }) => {
  // same as before
  const [mode, setMode] = useState<Mode>("light");

  // memoising the object!
  const theme = useMemo(() => ({ mode }), [mode]);

  return (
    <ThemeContext.Provider value={theme}>
      <button onClick={() => setMode(mode === 'light' ? 'dark' : 'light')}>Toggle theme</button>
      // the rest is the same as before
    </ThemeContext.Provider>
  )
}
```

And extract the new knowledge into the final rule of this article:

> <b>Rule #4</b>: When using context, make sure that value property is always memoised if it’s not a number, string or boolean.


## Bringing it all together

And finally, our app is complete! The entire implementation is <a href="https://codesandbox.io/s/re-renders-final-good-luz8s?file=/src/country-settings/page.tsx">available in this codesandbox</a>. Throttle your CPU if you’re on the latest MacBook, to experience the world as the usual customers are, and try to select between different countries on the list. Even with 6x CPU reduction, it’s still blazing fast! 🎉

And now, the big question that I suspect many people have the urge to ask: “But Nadia, React is blazing fast by itself anyway. Surely those ‘optimisations’ that you did won’t make much of a difference on a simple list of just 250 items? Aren’t you exaggerating the importance here?“.

Yeah, when I just started this article, I also thought so. But then I implemented that app in the “non-performant” way. <a href="https://codesandbox.io/s/re-renders-final-bad-4znwe?file=/src/country-settings/page.tsx">Check it out in the codesandbox</a>. I don’t even need to reduce the CPU to see the delay between selecting the items 😱. Reduce it by 6x, and it’s probably the slowest simple list on the planet that doesn’t even work properly (it has a focus bug that the “performant” app doesn’t have). And I haven’t even done anything outrageously and obviously evil there! 😅

So let’s refresh **when React components re-render**:

- when props or state have changed
- when parent component re-renders
- when a component uses context and the value of its provider changes

And the rules we extracted:

**Rule #1**: If the only reason why you want to extract your inline functions in props into `useCallback` is to avoid re-renders of children components: don’t. It doesn’t work.

**Rule #2**: If your component manages state, find parts of the render tree that don’t depend on the changed state and memoise them to minimize their re-renders.

**Rule #3**. _Never_ create new components inside the render function of another component.

**Rule #4**. When using context, make sure that `value` property is _always_ memoised if it’s not a number, string or boolean.

That is it! Hope those rules will help to write more performant apps from the get-go and lead to happier customers who never had to experience slow products anymore.

## Bonus: the `useCallback` conundrum

I feel I need to resolve one mystery before I actually end this article: how can it be possible that `useCallback` is useless for reducing re-renders, and why then React docs literally say that “[useCallback] is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders”? 🤯

The answer is in this phrase: _“optimized child components that rely on reference equality”_.

There are 2 scenarios applicable here.

**First**: the component that received the callback is wrapped in `React.memo` and has that callback as a dependency. Basically this:

```tsx
const MemoisedItem = React.memo(Item);

const List = () => {
  // this HAS TO be memoised, otherwise `React.memo` for the Item is useless
  const onClick = () => {console.log('click!')};

  return <MemoisedItem onClick={onClick} country="Austria" />
}
```

or this:

```tsx
const MemoisedItem = React.memo(Item, (prev, next) => prev.onClick !== next.onClick);

const List = () => {
  // this HAS TO be memoised, otherwise `React.memo` for the Item is useless
  const onClick = () => {console.log('click!')};

  return <MemoisedItem onClick={onClick} country="Austria" />
}
```

**Second**: if the component that received the callback has this callback as a dependency in hooks like `useMemo`, `useCallback` or `useEffect`.

```tsx
const Item = ({ onClick }) => {
  useEffect(() => {
    // some heavy calculation here
    const data = ...
    onClick(data);

  // if onClick is not memoised, this will be triggered on every single render
  }, [onClick])
  return <div>something</div>
}
const List = () => {
  // this HAS TO be memoised, otherwise `useEffect` in Item above
  // will be triggered on every single re-render
  const onClick = () => {console.log('click!')};

  return <Item onClick={onClick} country="Austria" />
}
```

None of this can be generalised into a simple “do” or “don’t do”, it can only be used for solving the exact performance problem of the exact component, and not before.

And now the article is finally done, thank you for reading it so far and hope you found it useful! Bleib gesund and see ya next time ✌🏼

...

Originally published at [https://www.developerway.com](https://www.developerway.com). The website has more articles like this 😉

[Subscribe to the newsletter](https://www.developerway.com), [connect on LinkedIn](https://www.linkedin.com/in/adevnadia/) or [follow on Twitter](https://twitter.com/adevnadia) to get notified as soon as the next article comes out.