DEV Community

Cover image for Understanding performance problems in React
Alexandru-Dan Pop
Alexandru-Dan Pop

Posted on Edited on Originally published at alexandrudanpop.dev

Understanding performance problems in React

The demo below is a deliberately slow example from 2020.

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
  • Measure production builds; development checks add overhead

Forms

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

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

We have the following components representation:

react components example

So, to render this - React created the following VDOM:
VDOM1

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

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

faker.fake("{{hacker.verb}}")
Enter fullscreen mode Exit fullscreen mode

to get a new option, React updates changed option values and text. The existing DOM nodes can be reused.

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

Inspect-View

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:

In this example, updating Form renders its children again. Rendering and updating the DOM are separate steps.

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

What to improve

Keep option data stable and move input state closer to the input. Profile before adding memoization.

If you like this article, chances are you will also enjoy what I post on Twitter. 🔥

More interesting reads:

Top comments (0)