Skip to content

Docs Clarification: Deriving vs Syncing Approach for things like two-way bound inputs #15955

Closed
@mithi

Description

@mithi

Describe the problem

I’d like to suggest to add a few more details to the docs around the “When not to use $effect section — particularly the "money spent / money left" example.

The current recommendation is to remove two $effects (which makes perfect sense!), and instead use two $state variables (spent and left) that are kept in sync manually.

The $derived docs says that derived values can be overridden — which makes me wonder: is there a specific reason why$derived is not used in this case? Is it bad practice? Perhaps it's related to how Svelte handles reactivity or performance under the hood?

Describe the proposed solution

In the case of two-way bound sliders:

<label>
  <input type="range" bind:value={() => spent, updateSpent} max={total} />
  {spent}/{total} spent
</label>

<label>
  <input type="range" bind:value={() => left, updateLeft} max={total} />
  {left}/{total} left
</label>

What is intuitive for me is to write it with a derived value:

(View in Playground)

<script>
  const total = 100; // use const to convey intention 
  let spent = $state(0);
  let left = $derived(total - spent);

  function updateSpent(newSpent) {
    spent = newSpent;
  }

  function updateLeft(newLeft) {
    spent = total - newLeft;
  }
</script>

However, the recommendation in the docs is to use two states and keeps them in sync manually:

(Playground Example From the Docs)

<script>
  let total = 100;
  let spent = $state(0);
  let left = $state(total);

  function updateSpent(value) {
    spent = value;
    left = total - spent;
  }

  function updateLeft(value) {
    left = value;
    spent = total - left;
  }
</script>

Could the docs clarify if it is ok to use $derived in above scenario and in which scenarios should manually syncing $state be preferred? Maybe highlighting the trade-offs (e.g. reactivity, clarity, potential pitfalls) would really help newcomers like me build accurate mental models around Svelte’s reactivity patterns.

Thanks for all all the amazing work the team has put in — the new reactivity model is genuinely a joy to use!

Update: Best Solution

<script>
  const total = 100; // use const to convey intention 
  let spent = $state(0);
  let left = $derived(total - spent);

  function updateLeft(newLeft) {
    spent = total - newLeft;
  }
</script>

<label>
  <input type="range" bind:value={spent} max={total} />
  {spent}/{total} spent
</label>

<label>
  <input type="range" bind:value={() => left, updateLeft} max={total} />
  {left}/{total} left
</label>

Importance

nice to have

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions