keepcalculator

06 Numbers and Powers

Why React Calls Your API Twice & What Stops It

Card No. 06·41363 · Updated · Standard formula, shown below

React calls your API twice in development because StrictMode intentionally double-invokes effects and component functions to surface bugs. In production builds, this does not happen; the duplicate call is a development-only behavior that you can stop by removing StrictMode or by writing an idempotent cleanup in your effect.

Background: Why StrictMode Exists

React’s StrictMode is a development tool that helps you find problems before they reach users. It was introduced in React 16.3 as a way to opt into extra checks and warnings. One of its key behaviors is double-invoking certain functions: the component body, state updater functions, and useEffect callbacks. This is not a bug—it is a deliberate feature.

The double-invocation is designed to make your code resilient to unmounting and remounting, which happens in real apps when a user navigates away and back, or when a component’s position in the tree changes. By running your effect twice, StrictMode forces you to notice if you are relying on side effects happening only once. If your API call is not idempotent (that is, calling it twice produces a different result), you will see the problem immediately in development instead of in production.

How StrictMode Triggers the Double Call

When you wrap your app in <React.StrictMode>, React runs the following in development only:

  • It mounts the component, runs the effect, then immediately unmounts it (simulating a cleanup).
  • It remounts the component and runs the effect again.

This means your useEffect with an API call like fetch('/api/data') will fire twice in the console. The same happens for useMemo, useReducer, and the render function itself. In production, StrictMode does nothing—it is a no-op. So the duplicate call only appears when you run npm start or yarn dev.

What Actually Stops the Double Call

There are several ways to prevent the duplicate request, depending on your goal.

Option 1: Remove StrictMode (Not Recommended)

You can simply delete <React.StrictMode> from your index.js or main.jsx. This stops the double invocation immediately. However, you lose the safety net that catches other bugs like impure renders or missing cleanup. Most developers keep StrictMode and fix their code instead.

Option 2: Write a Proper Cleanup Function

The recommended approach is to make your effect safe to run twice. In useEffect, you can return a cleanup function that cancels the first request before the second one starts. For example:

useEffect(() => {
  const controller = new AbortController();
  fetch('/api/data', { signal: controller.signal })
    .then(res => res.json())
    .then(setData);
  return () => controller.abort();
}, []);

With an AbortController, the first fetch is aborted when the cleanup runs, so only the second request actually completes. This is the cleanest solution because it also handles unmounting during navigation.

Option 3: Use a Ref or Module-Level Flag

If you cannot cancel the request (e.g., you are using a library that does not support abort), you can use a useRef to track whether the effect has already run:

const didFetch = useRef(false);
useEffect(() => {
  if (didFetch.current) return;
  didFetch.current = true;
  fetch('/api/data').then(...);
}, []);

This works because the ref persists across the simulated unmount/remount. However, it is a bit hacky and does not help with cleanup on real unmounts. Use it only when you have no other option.

Common Misconceptions

Many developers think the double call is caused by React Router, by the browser, or by their own code. In reality, it is almost always StrictMode. Another misconception is that the double call happens in production—it does not. You can verify this by building your app (npm run build) and serving it; the API will be called once.

Some also believe that the double call is a performance problem. It is not a performance issue in development because it only runs once per mount, and the second request is often aborted. The real risk is that you might accidentally send a POST request twice, which could create duplicate records. That is exactly why StrictMode forces you to handle it.

How to Verify the Cause

If you are not sure whether StrictMode is the culprit, do this:

  1. Open your browser’s Network tab.
  2. Refresh the page and watch the API request.
  3. If you see two identical requests, temporarily remove <React.StrictMode> from your entry file.
  4. Refresh again. If only one request appears, StrictMode was the cause.

You can also check the React DevTools—StrictMode shows a special icon in the component tree.

Alternatives to StrictMode

If you are using a framework like Next.js or Remix, StrictMode is often enabled by default. You can disable it in next.config.js or remix.config.js, but again, it is not recommended. Some teams use a custom hook that debounces or deduplicates API calls, but that is overkill for a development-only issue. The simplest alternative is to keep StrictMode and adopt the cleanup pattern.

Frequently Asked Questions

Does StrictMode double-call in production?

No. StrictMode is a development-only wrapper. In a production build, it has no effect, and your API will be called exactly once. You can confirm by building your app and inspecting the network traffic.

Why does my POST request get sent twice?

If you are using useEffect to send a POST, StrictMode will trigger it twice in development. This can create duplicate records. The fix is to abort the first request or to use a ref to skip the second invocation. In production, it will only send once.

Is it safe to remove StrictMode?

It is safe in the sense that your app will work, but you lose valuable warnings about impure renders, legacy lifecycle methods, and other potential bugs. It is better to keep StrictMode and fix your code to handle the double invocation.

Does React Query or SWR double-fetch too?

Yes, if you use them inside a useEffect that is wrapped by StrictMode, they will also fire twice. However, these libraries often have built-in deduplication, so you might only see one network request. If you see two, use their deduplication options or abort the first request.

Will the double call happen if I use useCallback?

No. useCallback does not affect how many times the effect runs. The double call is caused by StrictMode remounting the component, regardless of how you memoize the callback.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →