-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Description
Describe the problem
State is great to automatically track all deep changes made to data and perform precise (fine-grained) updates based on these changes. But, it comes with downsides, such as performance issues with large data due to proxies, and the fact that you can no longer perform equality checks.
To get around this, $state.raw()
exists. But it, too, has downsides: you can no longer track deep changes to data, for example, you can no longer use regular JS like Array.push()
, like you do with regular state. An example of such a use case, is when you have a large array of immutable objects, for example table rows:
<script>
let data = $state([])
// data is manipulated in many ways, like
data.push(a, b, c)
data.splice(n, 1)
data[5] = replaced
</script>
<!-- display data with pagination etc. -->
If there is too much data (thousands of elements), you will encounter massive performance issues due to the proxies. For this reason, $state.raw()
was added, but using this means you have to update the code that you use to modify the data:
data = [...data, a, b, c]
data.splice(n, 1)
data = [...data] // can't even do data = data, like in Svelte 4
data[5] = replaced
data = [...data]
A better option so you don't have to copy the array each time might be to use a store, which allows updating without changing the value reference. Regardless, you still lose fine-grained updated, i.e. data[5]
causes the entire {@each}
to rerun, for example.
Describe the proposed solution
Allow proxifying data partially. For example, to solve the case above:
let data = $state.shallow([])
This proxifies the array itself, but not any of the inner elements, so you can still get fine-grained updates based on the array itself, just like you'd get for an array of primitives, like numbers. Now, this is just a public API suggestion, but if $state
were to be allowed in object/array literals, this could be used like:
let data = $state({
config: {...} // deeply reactive,
items: $state.shallow([]), // array items are not proxied
map: $state.shallow({}), // also works with objects used as key/value pairs
other: $state.raw(...), // fully opt-out of proxies for this specific property
})
Note that this is similar to, but not the same as #15689; specifically, a major point of this is $state.shallow()
(or whatever syntax it may be, like$state(..., { depth: 1 })
), for arrays or key/value pairs.
Importance
would make my life easier