Web Applications

Why Your React App Re-Renders Twice on Every Click

You click a button, and a quick log shows your React component rendered twice. It feels like a bug, and sometimes it points to one, but often it’s React doing exactly what it’s told. Knowing which is which saves hours of chasing ghosts.

Illustration of a web application dashboard, Why Your React App Re-Renders Twice on Every Click
Your React app renders twice on a click.

Rule out Strict Mode first

In development with Strict Mode on, React intentionally renders components twice to surface side effects that aren’t safe. This only happens in development and disappears in production. Before debugging, confirm whether you’re seeing a real double render or Strict Mode’s deliberate one.

The React documentation on Strict Mode lists what gets doubled: component bodies, state initializers and reducers run twice, and effects run setup, cleanup and setup again when a component mounts. That last part is why a fetch inside useEffect can appear twice in the Network tab during development. It is a test, not a fault.

The quickest check is a production build. Run it locally, repeat the click, and count again. If the double render is gone, Strict Mode was the cause and your code is fine. Do not switch Strict Mode off to make the logs quieter. It is catching effects that would misbehave later, for example when a component unmounts and mounts again.

How to tell why React renders twice for real

If the extra render survives a production build, measure before you change anything. Guessing leads to useMemo on everything and no improvement.

  1. Open the React DevTools Profiler, record one click, and look at which components rendered and how many commits happened.
  2. Read the reason. The Profiler can record why each component rendered, such as changed props, changed state or a parent render.
  3. Turn on render highlighting in the DevTools settings, so components flash on screen as they render.
  4. Check the commit count. Two commits for one click points at state. One commit with many components points at structure.
Infographic summarising “Why Your React App Re-Renders Twice on Every Click”: Rule out Strict Mode first; How to tell why React renders twice for real; Then look at state and props; Fewer renders by design
The article at a glance.

Then look at state and props

Updating state in a way that triggers a second render is common: setting two separate state values in one handler, where one depends on the other, can cause an extra pass. Batch related state into a single update or a reducer so one event produces one render.

Since React 18, updates inside the same event handler are batched automatically. So in practice, the second pass usually comes from an effect. A useEffect watches one value and sets another, which means one render for the click and another for the effect. If the second value can be calculated from the first, calculate it during render and do not store it at all.

State that lives too high is another cause. When state sits in a parent, every change re-renders the whole subtree, even components that don’t use it. Move state down to where it’s actually needed, or split context so unrelated consumers don’t re-render together.

Context deserves a closer look. If a provider builds its value as a new object on every render, every component that reads that context renders again, even when nothing inside changed. Keep fast-changing values like form input in their own context, apart from slow ones like the signed-in user.

Unstable props are the third: passing a new object or function created inline on every render makes children re-render even when nothing changed. Memoize values and callbacks passed down. Rule out Strict Mode, then the fix is usually fewer, better-scoped state updates, not memoization sprinkled everywhere.

A typical example is style={{ margin: 8 }} or onSave={() => save(id)} written inline. Each render creates a fresh object or function, so a memoized child sees a new prop and renders anyway. Move constant objects outside the component, and wrap callbacks in useCallback only where a memoized child actually receives them.

Common mistakes

  • Using useCallback without memo. A stable callback only helps if the child is wrapped in memo or uses it as an effect dependency.
  • Random or index keys on lists that change. A key that changes forces React to throw the component away and mount it again, which is worse than a re-render.
  • Treating every re-render as a problem. Renders are cheap. Fix the ones that are slow or that the user can feel.

If your project uses the React Compiler, much of the manual memoization is handled for you. It does not fix state that lives in the wrong place, though, so the advice above still applies.

Fewer renders by design

Some renders disappear when less of the page runs in the browser at all. In Next.js, keeping static parts as server components leaves fewer client components to re-render, as I explain in server components vs client components. The same thinking removes the classic login flash, covered in handling auth redirects in Next.js without the flicker.

Rendering surprises also look different outside a normal page. In a browser extension, the popup mounts fresh every time it opens, so state you expected to survive is gone. I cover that and other traps in building a Chrome extension with React. If a React app is fighting you on performance and you want it looked at properly, that is part of my web application development work.

Questions people ask

Why does my React component render twice?

In development, the most common reason is Strict Mode, which deliberately runs component bodies twice to expose unsafe side effects. It does not happen in a production build. If the double render survives in production, look for an effect that sets state after the first render, state kept too high in the tree, or new objects passed as props.

Does React Strict Mode render twice in production?

No. The double rendering and the extra effect setup and cleanup only happen in development. Production builds render once per update. That is why the quickest test for a suspected double render is to build the app for production, run it locally, and repeat the action.

Why does useEffect run twice in React?

With Strict Mode on in development, React mounts a component, runs its effects, cleans them up and runs them again. This checks that your cleanup works. If an effect breaks when run twice, such as a subscription that is never removed, fix the cleanup rather than turning Strict Mode off.

Should I wrap every component in memo to stop re-renders?

No. Most renders are cheap, and memoizing everything adds complexity with little gain. Measure with the React DevTools Profiler first, then fix the cause: move state closer to where it is used, split busy contexts, and memoize only the components the profiler shows are slow.

Comments

Leave a comment

0 / 3000
Comments are moderated. Links are not clickable and your email is never published. See the privacy policy.
keep reading

Related articles

Usually replies within a day
let’s talk

Tell me what you want to build

A website, an app, some automation, or something you’re still figuring out. Tell me the problem and I’ll give you a straight answer on what it takes. No pressure, no sales team.