Skip to content

Nested deriveds for nested state changes and invalid state_referenced_locally warning #17602

@rChaoz

Description

@rChaoz

Describe the bug

I have a state like this:

let data = $state({ nested: { id: 123, otherFields: ... }});

The ID is used to get more data using an expensive calculation:

const moreData = $derived(expensiveCalculation(data.nested.id))

This is meant to rerun whenever ID changes, but unfortunately that's not the case - it reruns whenever data, data.nested or data.nested.id are assigned to. In my case, data is constantly received from the server using a WebSocket:

socket.on('data', (data) => {
  data.nested = data
})

Although the new data has the same ID, the expensive calculation re-runs every time, causing issues.

The first instinct is to extract the ID into its own derived:

const id = $derived(data.nested.id)

It works, but this is in a large component with many top-level fields, so I also tried something else to avoid top-level namespace pollution:

const moreData = $derived.by(() => {
	const id = $derived(() => data.nested.id);
	return expensiveCalculation(id)
});

Bug

This gives me a state_referenced_locally warning, but it works correctly. Nothing seems wrong with this solution IMO, so I think the warning is faulty - reading any state/derived outside of a closure in reactive scopes (effect, derived) should not be a warning.

Feature suggestion

This is somewhat similar in nature to #17308. I wish I could simplify the above solution into this:

const moreData = $derived(expensiveCalculation($derived(data.nested.id)))

Reproduction

https://svelte.dev/playground/ddff77a7351e43eda8cf2580ebf97416?version=5.49.1

Severity

annoyance

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