If your React component renders twice when you open a page, update state, or run an effect, the cause may be React Strict Mode rather than a bug in your application. React intentionally performs additional checks in development to identify impure rendering logic, missing cleanup functions, and unsafe side effects. However, repeated rendering can also result from state updates, parent component renders, changing dependencies, or application logic.
The key distinction is that rendering twice does not necessarily mean React displays the component twice or that your application has a performance problem. You need to identify whether React is calling the component function again, running an effect again, or actually creating duplicate operations.
This guide explains why React components render twice, how Strict Mode behaves, and how to fix common problems without hiding bugs.
Why Does a React Component Render Twice?
The most common reason is <StrictMode> being enabled in development. React deliberately calls component functions an extra time to check whether their rendering logic is pure. It also performs an additional effect setup-and-cleanup cycle when the relevant Strict Mode checks apply.
Other possible causes include:
- A state update triggers another render.
- A parent component renders again.
- Props or context values change.
- An effect runs again because its dependencies change.
- Development tools refresh the component during editing.
- Your application logic repeatedly updates state.
These situations are not equivalent. A component function running twice is different from an effect running twice, and both differ from a component being mounted twice.
The official React Strict Mode documentation explains which additional checks React performs and why they are useful.
What Is React Strict Mode?
React Strict Mode is a development-only tool that helps developers detect problems before those problems affect users. You enable it by wrapping a component tree in the built-in StrictMode component.
For example:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
createRoot(document.
getElementById('root'))
.render(
);
With Strict Mode enabled at the application root, React performs additional development checks, including calling component rendering logic twice and testing whether effects correctly clean up after themselves.
These checks do not mean React intentionally renders every component twice in production. The extra Strict Mode checks are development-only.
Let’s Figure It Out.
Tell us what you’re working on and we’ll help you identify the right next step.
Talk to an ExpertWhy Does React Call Components Twice?
React components should behave like pure functions: given the same props, state, and context, they should produce the same JSX without changing external data during rendering.
Consider this example:
function ProductList({ products }) {
products.push({ id: 99, name: ‘New Product’ });
return (
<ul>
{products.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
}
The problem is that push() modifies the array received through props. If React calls this component again, the modification can happen again, potentially creating duplicate entries.
A safer implementation creates a new array:
function ProductList({ products }) {
const items = [
…products,
{ id: 99, name: ‘New Product’ }
];
return (
<ul>
{items.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
}
Now the original array remains unchanged. Each render calculates its output without modifying the data supplied by the parent.
This is the purpose of double rendering: it helps expose code that accidentally depends on being executed exactly once. React’s Rules of React explain why components should remain pure and why side effects should stay outside rendering.
Why Does React useEffect Run Twice?
A common source of confusion is an effect that appears to execute twice immediately after a component mounts.
For example:
import { useEffect } from ‘react’;
function Dashboard() {
useEffect(() => {
console.log(‘Dashboard mounted’);
}, []);
return <h1>Dashboard</h1>;
}
The empty dependency array means the effect does not re-run simply because ordinary renders occur with unchanged dependencies. However, with root-level Strict Mode enabled, React performs an additional development-only effect cycle.
Conceptually, the sequence is:
- React renders the component.
- React runs the effect’s setup function.
- React runs its cleanup function.
- React runs the setup function again.
In the example above, there is no cleanup function, so the console message may appear twice.
This behavior is intentional. React is checking whether the effect can safely start, stop, and start again. It is particularly important for subscriptions, connections, event listeners, and other operations that interact with systems outside React.
One important detail: if Strict Mode wraps only a nested part of the application rather than the root, React does not perform the extra initial effect cycle in situations where that would produce a parent-child effect sequence that cannot occur in production.
How to Fix React Effects That Run Twice
The correct solution is to make effects safe to repeat, not to force React to execute them only once.
1. Add a Cleanup Function
Suppose a component subscribes to browser events:
import { useEffect } from 'react';
function ScrollTracker() {
useEffect(() => {
const handleScroll = () => {
console.log(window.scrollY);
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return Scroll tracking is active.
;
}
The cleanup function removes the exact listener registered by the effect. When React tests the effect in Strict Mode, the initial listener is removed before another listener is registered.
Without cleanup, repeated setup can leave multiple active listeners, causing the handler to run several times for one scroll event.
The same principle applies to timers, WebSocket connections, subscriptions, and third-party widgets. If setup creates something that must later be stopped or undone, implement the corresponding cleanup.
2. Handle API Requests Correctly
Fetching data inside an effect is common, but developers can mistake duplicate development requests for a broken rendering system.
A request can be made twice during the Strict Mode setup cycle. The first request may still reach the server even if its result is no longer needed.
For requests that become irrelevant when an effect is cleaned up, use an AbortController where supported:
import { useEffect } from 'react';
function ScrollTracker() {
useEffect(() => {
const handleScroll = () => {
console.log(window.scrollY);
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return Scroll tracking is active.
;}
This example cancels an outstanding fetch when cleanup runs. It does not guarantee that the server never received the request, but it helps prevent an obsolete request from updating the component after cancellation.
For requests that cannot be cancelled, use an appropriate stale-result guard. For more complicated data fetching, a framework-supported loader or a data-fetching library can manage caching and request deduplication.
If users rapidly change filters or navigate between pages, request ordering also matters. See [INTERNAL LINK: How to Prevent Race Conditions in React API Calls When Users Change Pages or Filters Quickly] for the related problem of preventing older responses from overwriting newer results.
3. Do Not Use Effects for User Actions
Some operations should happen only after a specific user interaction, not whenever a component mounts.
For example, avoid sending a purchase request from an effect:
useEffect(() => {
fetch(‘/api/buy’, { method: ‘POST’ });
}, []);
This is risky because a remount can trigger the operation again. A purchase should normally be initiated by a button handler:
async function handleBuy() {
await fetch(‘/api/buy’, {
method: ‘POST’
});
}
return <button onClick={handleBuy}>Buy now</button>;
This connects the purchase to the user’s action rather than component initialization. For payments and other important operations, the backend should also enforce appropriate idempotency or duplicate-submission protection. Moving a request into a click handler alone does not prevent every possible duplicate transaction.
Other Reasons React Components Re-Render
Strict Mode is not the only explanation for repeated rendering.
State Updates
Calling a state setter can trigger another render when the new state differs from the current state.
import { useState } from ‘react’;
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
Here, another render is expected after the button changes the count. React also batches state updates in many situations, so multiple setter calls do not necessarily produce an equal number of renders.
Parent Component Re-Renders
When a parent renders again, its children may also render. This can happen even if a child’s visible output does not change.
Do not immediately add React.memo to every component. First establish whether repeated rendering creates a measurable performance problem. Memoization can help in suitable cases, but it introduces its own comparison and maintenance considerations.
Effect Dependencies
An effect without a dependency array runs after every commit. An effect with dependencies runs again when React determines that a dependency has changed.
useEffect(() => {
console.log(‘Effect executed’);
}, [filters]);
If filters is a new object on every render, React can treat it as a changed dependency even when its contents appear identical. Depending on the code, you may need to move object creation inside the effect, use stable dependencies, or restructure the logic.
If an effect updates state that changes one of its own dependencies, it may also create a repeated render-effect cycle. Check the dependency values and state updates rather than assuming Strict Mode is responsible.
How to Debug Double Rendering Step by Step
Use this process to identify the actual cause:
- Check the environment. Determine whether the behavior occurs in development, production, or both.
- Inspect Strict Mode. Look for a <StrictMode> wrapper in your React entry point or framework configuration.
- Separate render logs from effect logs. Place one log in the component body and another inside the effect. They measure different events.
- Inspect cleanup logic. Confirm that listeners, timers, connections, and other resources are released properly.
- Check state and dependencies. Look for state setters, changing object references, and effects that update their own dependencies.
- Reproduce the issue in a production build. Use the framework’s supported production build and test the same user flow. Do not rely solely on development console counts to assess production performance.
- Measure before optimizing. Use React Developer Tools and its Profiler to identify expensive renders before adding memoization.
Also check whether your development environment is performing a refresh after code edits. Fast Refresh can preserve or reset component state depending on the changes, making development logs look different from an ordinary page load.
For related frontend stability issues, you can also connect this article to [INTERNAL LINK: How to Fix Cumulative Layout Shift (CLS) and Stop Your Website Layout from Jumping]. If your application displays user-generated content, [INTERNAL LINK: How to Prevent Cross-Site Scripting (XSS) Attacks in React and JavaScript Applications] covers a separate but important React security concern.
Should You Disable React Strict Mode?
Usually, no. Disabling Strict Mode may hide symptoms without correcting the underlying problem.
A component that leaks event listeners or performs unintended operations during rendering can still fail when it is remounted for other reasons. Strict Mode helps expose those weaknesses during development.
Investigate duplicate logs, verify cleanup behavior, and make rendering pure before considering configuration changes. If the component behaves correctly under the extra development checks and the production build performs as expected, there may be nothing to fix.
Conclusion
A React component rendering twice is often normal development behavior, particularly when root-level Strict Mode is enabled. The important question is whether repeated rendering reveals an actual bug.
Keep component rendering pure, clean up effects, handle obsolete API requests, and place user-triggered operations in event handlers. Check state updates and effect dependencies when the behavior continues outside the initial Strict Mode cycle.
These practices make React applications more predictable, easier to debug, and safer to maintain as their component trees and data flows become more complex.
8. Frequently Asked Questions (FAQs)
1. Why does my React component render twice on the first load?
Your component may render twice because React Strict Mode performs an extra development-only render to detect impure component logic. If Strict Mode is enabled at the root, React also runs an extra effect setup-and-cleanup cycle. Check your React entry point before assuming the behavior is a bug.
2. Does React Strict Mode cause double rendering in production?
No. Strict Mode’s extra rendering and effect checks are development-only. A production application can still render multiple times because of state changes, parent renders, or other normal React behavior, but the extra Strict Mode checks are not performed in production.
3. How do I stop useEffect from running twice in React?
First, determine why the effect runs again. If root-level Strict Mode triggers an additional setup cycle, implement a cleanup function that reverses the effect’s setup. Also verify the dependency array and avoid putting user-triggered operations, such as purchases, inside effects merely to run them on mount.
4. Why does React make two API calls when a component mounts?
An effect that fetches data can run through an additional setup cycle in development when Strict Mode is enabled. This can produce two network requests. Use cancellation or stale-result handling where appropriate, and consider a data-fetching library that supports caching and request deduplication. Do not assume cancelling a request means the server never received it.
5. Should I remove Strict Mode to fix duplicate rendering?
Generally, no. Removing Strict Mode hides the additional checks but does not fix impure rendering, missing cleanup, or unsafe effects. Keep Strict Mode enabled while debugging so that you can identify and correct problems before they affect application behavior.
6. Why does my React component keep re-rendering even without Strict Mode?
Repeated rendering can result from state updates, parent component renders, changed props or context, and effects that update their dependencies. Check the component’s state setters and effect dependencies, then use React Developer Tools Profiler to determine whether the renders are unnecessary or causing measurable performance issues.
Let’s Talk About Your Business
Not sure which approach is right for your business? Get a free consultation with our team.
Get Free Consultation