Understanding performance problems in React
Tags: react, javascript
Published: 2020-05-12 14:28:53

Before digging deeper into what can create performance problems in your React application, please take note of the following:
- React is pretty fast by default, hence premature optimizations are not needed
- React performance is different than your custom components performance
- React's dev mode performance is much worse than React's build mode performance

## Recent talks
Now there have been a lot of talks lately about how to make the **VDOM** or **reconciliation** faster.

{% twitter 1256653235122851841 %}

**TLDR** - the discussions here are focusing on trying to find alternative methods to  **React's VDOM and reconciliation algos** - those being an **O(n)** timespace complexity.

If you are not familiar with the **Big O** notation - here are a few hints: 
> **O(1)** - algo executes in the same time regardless of the input data set
```js 
const getFirstItem = (someArray) => Array.isArray(someArray) && someArray[0]
```


> **O(n)** - algo performance depends linearly to its input data set (more data -> slower algo)
```js 
const toUpperCase = (someArray) => Array.isArray(someArray) && someArray.map(x => x.toUpperCase())
```

So getting back to React, for sure it's fast for a lot of things... but let's see where it doesn't actually shine.

## Forms
Yep. Forms - let's check out some code that I intentionally made pretty unperformant. 👨‍💻

```jsx
import React from "react";
import faker from "faker";

function Input({ onChange, value }) {
  console.log("Input - rendered");
  return <input type="text" onChange={onChange} value={value} />;
}

function DropdownItem() {
  console.log("DropdownItem - rendered");
  const option = faker.fake("{{hacker.verb}}");
  return <option value={option}>{option}</option>;
}

function Dropdown() {
  console.log("Dropdown - rendered");
  const [selected, setSelected] = React.useState("");

  return (
    <select
      value={selected}
      onChange={({ target }) => setSelected(target.value)}
    >
      {[...Array(1000)].map((_, i) => (
        <DropdownItem key={i} />
      ))}
    </select>
  );
}

function Form() {
  const [inputVal, setInputVal] = React.useState("");
  console.log("Form - rendered");

  return (
    <form>
      <h1> Form </h1>
      <Input
        value={inputVal}
        onChange={({ target }) => setInputVal(target.value)}
      />
      <Dropdown />
    </form>
  );
}

export default function App() {
  return (
    <div className="App">
      <Form />
    </div>
  );
}
```

We have the following components representation:  
![react components example](https://dev-to-uploads.s3.amazonaws.com/i/pnnpqapw7okj3y4xgd7b.PNG)

So, to render this - React created the following VDOM:
![VDOM1](https://dev-to-uploads.s3.amazonaws.com/i/fqo0hm7jr67cj9pboybg.PNG)

As we can see, **Input** is a controlled component that changes the **Form** state  every time the user types anything.

So when **Input** changes, React is creating a new VDOM tree starting at the component where something changed state or props -> the **Form** component: 
![VDOM2](https://dev-to-uploads.s3.amazonaws.com/i/akg99pqtwx3wazzrdt82.PNG)

Now it will diff the previous VDOM (the green one) and it will see that the **Input** component needs to be changed in the real DOM. But also since each **DropdownItem** component is calling 

```js
faker.fake("{{hacker.verb}}")
```

to get a new option - each of the 1000 **DropdownItems** components are re-created in the DOM as well. 

**DropdownItem** is an example of why you should try to keep components pure.

![Inspect-View](https://dev-to-uploads.s3.amazonaws.com/i/cwkrxlq5230ts3zp7yn4.gif)

## Key takeaway ✨
All our components have been computed to create **the new Virtual DOM** - including all our 1000 DropdownItems 😱. So if our own components code is slow and we combine that with the fact that we are rendering a big amout of those components at a high frequency (every time the user types something), then we can bring the VDOM to its knees pretty easily. 

Just to emphasize: 
> Every time a new VDOM is created, all your components code is executed

**React**, as all other technologies, has benefits and tradeoffs that we need to carefully consider.

{% twitter 1259600386094030848 %} 

## Topics for the next time
This will be a 2 or 3 parts article - so stay tuned for next time when we will fix all the performance issues and discuss how to better **engineer** our components to avoid those problems in the first place.

{% codesandbox cranky-feather-hbwgq runonclick=1 %}

If you like this article, chances are you will also enjoy what I post on [Twitter](https://twitter.com/alexandrudanpop). :fire:

More interesting reads: 
- [Correctly handling async/await in React components](https://dev.to/alexandrudanpop/correctly-handling-async-await-in-react-components-4h74)
- [Becoming a better FE developer in 3 steps](https://dev.to/alexandrudanpop/becoming-a-better-fe-developer-in-3-steps-2khn)
- [Tips to boost productivity as a FE developer](https://dev.to/alexandrudanpop/tips-to-boost-productivity-as-a-fe-developer-2ig9)