Ask
27

My $effect sets a value from other state and now runs twice and reads a stale value — what am I doing wrong?

Coming from an older reactive framework where a watcher that assigns to something else was completely normal.

I have a piece of state that should always be derived from two other pieces. I wrote an effect that reads both and assigns the result.

What happens: it runs more often than it should, occasionally reads a value that is one update behind, and once I got a warning about updating state in an effect. Adding a guard so it only assigns when the value changed made it less frequent and did not make it correct.

I can feel that I am fighting the framework rather than using it, but I do not understand the model well enough to know what the right shape is.

2 answers Share
Report

Answering anonymously — a moderator will review it first.

  • @derived_not_effect · 5h ago

    You are fighting it, and the fix is one word: that is not an effect, it is a derived value.

    The distinction is the whole model:

    • Derived is for state that is a pure function of other state. You describe what it is, the framework works out when to recompute it, and it is always consistent because it is computed on demand rather than pushed.
    • Effect is for reaching outside the reactive system — the DOM directly, a network call, a subscription, logging, a timer. Things with consequences that the framework cannot see.

    Writing state from an effect puts you outside the model and makes you responsible for the ordering, which is exactly the job the framework exists to do. That is why you got all three symptoms at once:

    Runs more often than expected — the effect depends on everything it read, including things you did not intend, and each of those triggers it.

    Reads a value one update behind — you have created a two-step update. Sources change, effect runs, effect writes, dependents update. Anything reading between steps one and three sees the old value. A derived value has no such window.

    The warning about updating state in an effect — that is the framework telling you precisely this.

    Declare it as derived and all three go away together, along with your guard.

    30
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @sync_is_the_smell · 5h ago

    The general rule I would take from this, because it applies well beyond this framework: "keeping two pieces of state in sync" is always a design problem wearing a timing problem's clothes.

    If B must always equal f(A), then B is not state. It is a view of A. Storing it separately creates a second source of truth and an obligation to maintain the relationship forever, and every bug you described is that obligation being violated somewhere.

    The cases where people think they need a real copy, and what to do instead:

    "It is expensive to compute." Derived values are cached and only recompute when their inputs change. This is already handled.

    "The user can edit it, so it is not purely derived." Now it genuinely is state — but then it should be initialised once, not synced continuously. An effect that keeps overwriting the user's edit is a bug you will hit next.

    "It comes from a request." Then the request is the effect, and what it produces is state. The derivation and the fetching are two different things and should be two different pieces of code.

    That third one is the honest use of an effect, and it is worth noticing how narrow the legitimate list is. Most effects in a codebase are derived values that have not admitted it yet.

    25
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report