You Might Not Need an Effect - discussion (2023-02-01)
The "You Might Not Need an Effect" article is a good reminder that many effects are just derived values or event handlers wearing an effect costume. In the React Tips vocabulary, it also maps to "make the contract explicit": if it's derived, store derived; if it's orchestration, name it and log it so it's observable.
What effect patterns did you remove after reading this, and what did you replace them with? How do you decide between derived-in-render, stored-derived, and a named orchestration effect? Do you log effect behavior as documentation (return strings) or keep effects silent?
Comments (18)
Back to latestThe biggest removal for us was "sync props to state" effects.
We either derive in render or treat the state as the source and stop pretending it's synced.
We started logging effect decisions as doc strings (React Tips style) so it's obvious what's happening:
txt
[tips] renderEffect=derive:summary reason=inputsChanged keys=3
[tips] flowEffect=nav:normalize reason=query:missingDefaults action=replaceState
The distinction helped: derive is pure-ish; flow is orchestration with intent.
Counterpoint: the article can be read as "never use effects" and that's not realistic.
Some things are genuinely imperative (measure DOM, subscriptions). The trick is making them bounded and observable.
Exactly. The win isn't banning effects, it's banning *mystery* effects.
If an effect exists, it should have a reason and show up in logs/evidence.
We replaced a bunch of effects with stored-derived selectors because multiple panels needed the same computed output.
It made the UI consistent and reduced reflow churn.
Heuristic that worked: if the effect writes state based on state, it's probably derived and should move.
If the effect coordinates external world (history, focus, network), it's orchestration and should be named.
We also stopped using effects for "fetch then setState" and moved to a render fetch posture.
The lane is explicit and the evidence is visible, so it feels less fragile.
Counterpoint: stored-derived can become a second source of truth if you write it from too many places.
If you do it, make derivation a single call site and log every derive reason.
We used useFlowEffect for the truly imperative stuff and made it return a doc string.
It turned "effects are scary" into "effects are documented".
I like the article's emphasis on event handlers.
A lot of effects were just "do something after click" when the click handler could do it directly.
Docs tie-in: the API reference + patterns pages here normalize named effects and evidence strings.
Related: API Reference and Patterns Library.
We introduced a tiny effect log buffer in dev and it revealed a lot of redundant work.
Once you can see effect spam, you can fix it.
Counterpoint: sometimes deriving in render causes perf issues if the derive is heavy.
We moved heavy derives to stored-derived and kept light derives in render.
We also stopped doing focus management in effects that run on every render.
Now we only do focus in response to explicit route motion intent and we log the reason.
The article pairs well with the idea of "multi-truth inputs".
If typing is draft truth, you don't need an effect to chase it into global truth.
A nice pattern is keeping an "intent log" separate from effects log.
Intent explains why; effects explain how. Both can be short strings.
I used to think effects were the default glue. Now I think they're the exception glue.
If something feels like glue, I first check if it's derived or an event.
One thing I'd add: if you keep effects, make them produce a readable artifact (log line, evidence key).
Otherwise they stay invisible and people will keep cargo-culting them.
This article is a nice forcing function: it makes you name your dependencies and your contracts.
Even when you keep the effect, the act of justifying it often improves the code.