Rendering — the performance trap that costs renders

Master rendering performance in React to avoid costly app slowdowns and pitfalls in interviews.

Optimizing a React application’s rendering is crucial. One key area where many developers falter is understanding how re-renders and component updates can affect performance, often leading to a noticeable lag, especially in larger applications. It's common to encounter performance issues that stem from improper usage of state and props, failing to manage component lifecycle methods correctly, or neglecting key rendering optimization techniques. Being aware of these pitfalls can be the difference between an efficient application and one that performs poorly in production.

Understanding Rendering in React

In React, rendering refers to the process of constructing and updating the UI in response to state or prop changes. Each time a component re-renders, it can potentially incur a performance cost. This happens because React must reconcile (compare) the new virtual DOM tree with the previous one to figure out what changed and what it needs to render. The challenge is to minimize the frequency and cost of these updates while ensuring the UI remains responsive.

To illustrate rendering, consider the following simplified example of a component that doubles an array of numbers:

import React, { useState } from 'react';

const NumberDoubler = () => {
  const [numbers, setNumbers] = useState([1, 2, 3, 4, 5]);

  const handleDouble = () => {
    const doubled = numbers.map(n => n * 2);
    console.log(doubled);
    setNumbers(doubled); // Triggers re-render
  };  

  return (
    <div>
      <button onClick={handleDouble}>Double Numbers</button>
    </div>
  );
};

export default NumberDoubler;

Here, the handleDouble function will update the state and trigger a re-render every time the button is clicked, which is expected. However, if this function were to be called repeatedly in quick succession, it could lead to a lag in performance due to excessive render cycles.

Common Rendering Issues

Issue What Happens
Unnecessary Re-renders Components unnecessarily update, causing lag.
Poor State Management Managing state inappropriately can cause frequent re-renders.
Improper Use of Keys Without unique keys in lists, reconciliation may be inefficient.
Ignoring Memoization Failing to use React.memo or useMemo for optimization leads to redundant calculations and renders.

Interview Traps

Candidates can miss critical aspects of rendering performance during interviews. Here are some specific traps to look out for:

  • Interviewers may ask about less effective optimizations and expect candidates to know why certain strategies don’t work.
  • Questions may focus on what specific code will output, expecting candidates to understand the implications of unnecessary re-renders.
  • Design principles regarding component separation (like container/presentational components) that enhance performance may be probed.
  • Candidates might be questioned on reconciliation, not just in terms of definitions but in understanding its impacts on rendering performance.

Worked Example

Let’s consider a situation where you have a list of items rendered as components:

const ItemList = ({ items }) => {
  return (
    <ul>
      {items.map(item => <Item key={item.id} item={item} />)}
    </ul>
  );
};

const App = () => {
  const [items, setItems] = useState(data);  // data is an array
  const [extraItem, setExtraItem] = useState('');

  const addItem = () => {
    setItems([...items, { id: Date.now(), name: extraItem }]);
  };

  return (
    <div>
      <input value={extraItem} onChange={e => setExtraItem(e.target.value)} />
      <button onClick={addItem}>Add Item</button>
      <ItemList items={items} />
    </div>
  );
};

In this example, every time a new item is added, the entire ItemList component re-renders. This could be optimized using React.memo for the Item component or restructuring the application to minimize re-renders only to affected components, such as using a separate state for added items.

Daily Impact in Production

In real-world applications, performance issues arise when there are a large number of components or when components have complex rendering logic. Neglecting to optimize for rendering leads to:

  • Increased Load Times: Longer waiting times for users, especially on mobile devices where resource efficiency is critical.
  • Poor User Experience: Lag or stutter when interacting with the application due to sluggish rendering.
  • Scaling Challenges: Adding more features becomes harder when the existing components are not optimized for rendering.

Ultimately, being vigilant about component structure, state management, and memoization can significantly improve the performance of React applications and, by extension, your own coding practice.

References

Practice

Ready to practice Rendering?

Answer real questions, get instant feedback, and watch your skill score climb — free. Practice is in English, like real tech interviews.

Try one 👇

ReactHooksMid
0 XP
When does useEffect run by default?

↑ Go ahead — pick an answer. This is Skillpato.