Why can't you store promises in state?
What does "storing a promise in state" mean?
Example (the wrong way):
function User() {
const [userPromise, setUserPromise] = useState(fetch('/api/user').then(r => r.json()));
// trying to use it...
userPromise.then(user => console.log(user));
return <div>User profile</div>;
}At first glance it looks fine - the promise is stored in state, then you can "wait" for the result. But in practice this is an anti-pattern and a source of many problems.
Why this is a bad idea
1. Promises aren't serializable or deterministic
React expects state (state) to be deterministic data
that can be:
- compared (
Object.is(prev, next)), - reused across re-renders,
- reset and restored (e.g. for time-travel debugging in Redux DevTools).
But a promise:
- has no stable value (its result arrives later);
- changes on its own (resolve/reject outside React);
- cannot be serialized (cannot be saved to JSON or a snapshot).
React cannot tell exactly when it "changed",
so storing a promise in state violates the very idea of reactivity.
2. A promise creates a side effect during render
const [data, setData] = useState(fetch('/api/user').then(r => r.json()));Here fetch() runs on every render,
and there can be several renders (React 18 double-renders in Strict Mode).
As a result:
- new promises are created on every render;
- React cannot stop them;
- you get duplicate requests and leaks.
3. You can't safely use then inside a render
userPromise.then(data => setUser(data)); // a side effect in the component bodyThis breaks React's rule:
a render must be a pure function with no side effects.
An async operation inside the component body is a dirty render; React doesn't guarantee its order and can't correctly cancel or repeat it under Concurrent Rendering.
4. React doesn't know when the promise finished
React works on the principle:
"When
statechanges, the component needs to re-render."
But if you store the promise itself, not its result, React won't know when it resolves or rejects.
That means the UI will never update automatically:
const [userPromise, setUserPromise] = useState(fetch(...));
// even after the promise finishes, the component won't re-render5. Race conditions and stale data
If the component unmounts or receives new props,
the old promise can still finish and try to update state,
triggering:
Warning: Can't perform a React state update on an unmounted componentThe right way
Option 1. useEffect + state for the result
function User({ id }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let active = true;
setLoading(true);
fetch(`/api/users/${id}`)
.then(r => r.json())
.then(data => active && setUser(data))
.finally(() => active && setLoading(false));
return () => { active = false; }; // cleanup
}, [id]);
if (loading) return <p>Loading...</p>;
return <p>{user.name}</p>;
}Here:
- the promise is not stored in state;
- we store the promise's result (
user,loading,error); - React knows when to update the UI.
Option 2. Through React Query / SWR
Modern libraries take care of all this:
import { useQuery } from "@tanstack/react-query";
function User({ id }) {
const { data, isLoading } = useQuery({
queryKey: ['user', id],
queryFn: () => fetch(`/api/users/${id}`).then(r => r.json())
});
if (isLoading) return <p>Loading...</p>;
return <p>{data.name}</p>;
}React Query:
- does not store the promise in state;
- caches results;
- cancels stale requests;
- triggers a re-render when the data is ready.
Option 3. React.Suspense (for React 18+)
If you use Suspense for data, React itself "waits" for the promise under the hood,
but this is already a controlled mechanism, not a plain useState.
function User({ resource }) {
const user = resource.user.read(); // may throw a promise
return <p>{user.name}</p>;
}Here the promise is not manually stored in state,
React manages it inside the Suspense mechanism.
Summary
| Should not store | Can store |
|---|---|
the promise itself (Promise) | the promise's result (data, error, loading) |
| async effects during render | async effects in useEffect |
| unstable objects | stable state values |
| side effects in the function body | a pure function + an effect |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.