Essay · React & AI-Native Engineering
Deriving state is a correctness guarantee, not a performance trick
Your agent hands you clean, working, “optimized” React. It can still be wrong — in a way that won't surface until it costs you something.

One source of truth stays intact — the copies drift
The most expensive React bug I know doesn't throw. It quietly serves the wrong data.
You ask your agent for a product list with a search filter. Ten seconds later you have clean, working code. It even looks optimized — no obvious waste. You skim it, it renders, you move on. Here is what came back:
products. The day it changes without query changing, the list goes stale — silently.This passes review at most shops. It runs. It filters. And it is wrong — not slow, wrong — in a way that won't surface until it costs you something.
The reframe
The usual objection to storing derived state is performance: you triggered an extra render, you're doing work React could skip. True, and almost irrelevant. That extra render is a rounding error.
The real cost is correctness. The moment you copy products into results, you have a second source of truth. products knows the answer. results remembers one — the answer that was correct the last time the effect happened to run. Those two can disagree, and the entire job of that useEffect is to keep papering over the gap.
Look at the dependency array. It watches query. It does not watch products. So the day products changes without query changing — a refetch, a prop update, an optimistic insert — the list on screen is stale. No exception. No red console. No failing test, because the test filtered a static array. Just the wrong data, rendered with total confidence.
A stored copy of derivable data is a bug with a delay. It doesn't fail when you write it. It fails when the inputs drift — which is precisely when nobody is watching.
That is the shape of it: a production bug at midnight, on a weekend, that git blame traces back to a line everyone approved because it “looked optimized.”
The senior fix is shorter
No effect. No second state. No dependency array to forget. results cannot go stale because it does not persist — it is recomputed from products and query on every render, which makes it always exactly what those two inputs imply. There is nothing to keep in sync because there is nothing to sync.
If you can compute it, don't store it. State is only for what you cannot derive. Everything else is a function of state — and functions belong in render, not in memory.
This is not an argument against useEffect
Be precise here, because the lazy version of this take is “effects bad,” and that is wrong. useEffect is the correct tool for synchronizing with systems that live outside React: fetching data, opening a subscription, wiring up a non-React widget, touching the DOM directly. Those are real synchronization problems — two worlds that genuinely need reconciling.
Filtering an array you already hold is not that. It is a calculation, and store-and-sync uses a synchronization primitive to do arithmetic. The React docs have a page named for exactly this reflex — You Might Not Need an Effect — and the tell is the pattern above: an effect whose only job is to call setState with a value computed from other state or props. Effects for the outside world; derivation for everything you can calculate.
Link accessed Aug 2, 2026 · react.dev/learn/you-might-not-need-an-effect
Minimize your sources of truth
One authoritative value, derived everywhere it is needed. One source of truth means nothing to keep in sync, which means nothing can drift.
A decade in law taught me this before anything else: when two clauses can each claim to be binding, you don't have redundancy — you have a dispute. A component is no different.
How you keep this out of a codebase the AI mostly writes
This is the part that actually changed. The agent reaches for store-and-sync by default, because it is the statistically common pattern in its training data. You will not out-type that. You govern it instead.
- Make the guardrail explicit. Put it in your prompt and your project rules: prefer deriving values during render; never store in state what can be computed from existing state or props. You get the output you specify, and "optimize this" specifies nothing.
- Treat every generated line as something you must defend. If you can't say out loud why a value is state and not a derivation, it isn't reviewed — it's just present.
- Add one question to code review: is this state, or is it derivable? It catches this entire class of bug on sight.
- Turn on react-hooks/exhaustive-deps. It won't stop you from storing derived state, but it screams about the missing dependency that makes store-and-sync silently rot.
- Keep "You Might Not Need an Effect" as a review reflex, not a link you read once.
The skill that's left
Generating the component is no longer the work. The agent does that, and does it fast. What it can't do is own the decision — it will hand you a plausible second source of truth with a straight face and call it optimized.
The senior contribution is no longer the keystroke. It is the audit — reading what the agent decided, knowing which decisions drift, and defending every line as if you had typed it. Because in the only sense that matters, you did.
The shorter version filters a list. It also happens to be correct by construction. Those are the same decision — and knowing that is the job now.
Shipping AI-native software you need to trust?
I'm a senior fullstack engineer available for remote work — from architecture to auditing the code your agents write.