React
setState
performance
optimization
JavaScript

React setState takes 200ms

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

When setState appears to take 200 milliseconds, the problem is usually not the state setter itself. The real cost is almost always in the render work triggered by the update: expensive calculations, too many component re-renders, heavy DOM work, or large lists updating at once. To fix it, profile the update path instead of assuming the setter is inherently slow.

setState Schedules Work

In React, setState or a state setter from useState schedules an update. React then decides what needs to re-render and commits the necessary DOM changes.

jsx
1import { useState } from "react";
2
3export default function Counter() {
4  const [count, setCount] = useState(0);
5
6  return (
7    <button onClick={() => setCount(count + 1)}>
8      {count}
9    </button>
10  );
11}

The setter call itself is tiny. What becomes expensive is everything that happens after it.

Look for Expensive Rendering

A common issue is recomputing large derived values on every render.

jsx
1function SearchResults({ items, query }) {
2  const filtered = items.filter((item) =>
3    item.name.toLowerCase().includes(query.toLowerCase())
4  );
5
6  return (
7    <ul>
8      {filtered.map((item) => (
9        <li key={item.id}>{item.name}</li>
10      ))}
11    </ul>
12  );
13}

If items is large, a state update elsewhere can make this component expensive. Use memoization when the computation is stable relative to its inputs.

jsx
1import { useMemo } from "react";
2
3function SearchResults({ items, query }) {
4  const filtered = useMemo(() => {
5    return items.filter((item) =>
6      item.name.toLowerCase().includes(query.toLowerCase())
7    );
8  }, [items, query]);
9
10  return (
11    <ul>
12      {filtered.map((item) => (
13        <li key={item.id}>{item.name}</li>
14      ))}
15    </ul>
16  );
17}

Prevent Unnecessary Re-renders

If one small state change causes a large subtree to re-render, split components and memoize where appropriate.

jsx
1import React, { memo, useState } from "react";
2
3const ExpensiveChild = memo(function ExpensiveChild({ value }) {
4  return <div>{value}</div>;
5});
6
7export default function App() {
8  const [count, setCount] = useState(0);
9  const [text, setText] = useState("");
10
11  return (
12    <>
13      <button onClick={() => setCount((c) => c + 1)}>{count}</button>
14      <input value={text} onChange={(e) => setText(e.target.value)} />
15      <ExpensiveChild value="stable" />
16    </>
17  );
18}

If props do not change, memo can stop wasted work.

Profile Before Guessing

Use the React DevTools Profiler to see which components re-render and how long they take. That tells you whether the cost comes from reconciliation, large lists, layout thrashing, or third-party components.

Without profiling, developers often optimize the wrong layer.

Production Builds Matter

Always compare performance in a production build before drawing conclusions. Development mode includes extra warnings and validation work, and React Strict Mode may intentionally trigger additional render paths during development. A slow development build does not automatically mean the shipped application has the same problem.

If the lag still appears in production, then the profiler results are much more likely to reflect a real user-facing bottleneck.

That is the point where memoization, virtualization, or state-ownership changes usually become worth the complexity.

Until then, measure first and optimize second.

That avoids cargo-cult tuning.

Common Pitfalls

  • Blaming setState instead of the render and commit work that follows.
  • Performing expensive filtering, sorting, or mapping on every render.
  • Updating large lists without virtualization.
  • Passing new object and function props everywhere and defeating memoization.
  • Measuring performance in development mode only, where React does extra checks.

Summary

  • 'setState itself is usually not the slow part.'
  • Slow updates usually come from expensive renders or DOM work after the state change.
  • Use memoization, component splitting, and list virtualization where appropriate.
  • Profile with React DevTools before optimizing.
  • Optimize the update path, not just the setter call.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.