You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There are actually multiple options of how to use $state and $derived with different implications. Following decision trees help narrowing down when to use which option. There is a summary at the bottom with default recommendations when starting out.
Its tl;dr is:
When starting out...
...default to $state objects (called Deep State in the docs) for state, e.g., $state({ value: 0 }) or $state([0, 0]) or $state([{ value: 0 }])
...default to functions (instead of $derived) for derived state, e.g., () => someState
...understand that other options have their place too, so read the following to get a better understanding
If you don't understand the terms in the decision trees you can find examples below the trees.
There are even more options than described but I limited the trees to those options you are going to use IRL and where high flexibility, less boilerplate and overall DX are key.
$state
graph TD;
a(Does $state needs to be exported* or to be an object/array or to have methods?) -->|No| 1(__Option 1:__ $state primitive);
a -->|Yes| b;
b(Can you pass on type hints or does your state needs an embedded $derived as prop or do you need multiple instances?)-->|No| 2(__Option 2:__ $state object);
b -->|Yes| 3(__Option 3:__ class with Rune fields);
$state object (called Deep State in the docs): $state({ value: 0 })docs
class with Rune fields: class Something { value = $state(0); d = $derived(this.value) }docs
You get most features with class and the ability to create multiple instances but it has the most boilerplate and the most minimal type hints, actually none except the class name; $state primitive is pretty bare bone and needs to be refactored if you want more but it's lean and a $state object is somewhere in the middle with very slight performance overhead but gives you way better type hints than a class.
You can still use $state objects when needing $derived, you just embed a function instead. Putting a $derived outside as a dedicated constant declaration doesn't always work because it can't be exported. So, with option 2 and you might rarely run into limitations and don't need to refactor while with option 1 things are much more limited. Option 2 seems to offer the most balanced package regarding features, flexibility, performance and DX.
Bonus tip: Always use arrow functions within classes, so this refers to the lexical scope or where the function was defined.
Here the same info as a comparison chart:
$state primitive
$state object
Class with Rune fields
Can be exported?
-
y
y
Can be an object or array?
-
y
y
Can have methods?
-
y
y
Zero boilerplate?
9/10
6.5/10
5/10
Can have $derived props/fields?
-
-
y
Can have functions as derived state as props/fields instead?
-
y
y
Can create instances?
-
-
y
Full type hints?
y
y
-
No performance overhead (untested)?
y
-
y
Svelte 4 Stores can be embedded as props/fields
-
-
y
*This is actually "State needs write access and to be exported" but since $state always needs some write access at some point (otherwise why would I use $state?) it is shortened to "State needs to be exported".
$derived/$derived.by
graph TD;
a(Does $derived needs to be exported?) -->|No| 1(__Option 1:__ $derived as constant);
a -->|Yes| b;
b -->|No| 2(__Option 2:__ use a function instead);
b(Do you want to embed $derived into a class with Runes?)-->|Yes| 3(__Option 3:__ $derived as class field);
class ClassWRunes { someDerivedState = $derived(someState) }; export const classWRunes = new ClassWithRunes()
Once you want to export a $derived you need to embed it into a class with Runes which again has the most boilerplate and no type hints. It is easier to just use a function which can be embedded into $state object or just left outside and still be exported, in contrast to $derived.
Summary
While Runes give quite some options how to work with them it can be overwhelming when you just get started. All options have their place but to reduce complexity and mental overhead, you should have one default option in your mind and deviate when appropriate:
$state objects (Deep State in the docs) give you much higher flexibility than $state primitives, still less boilerplate-y than classes and excellent type hints in contrast to classes
$derived can't be exported, can't be embedded in $state objects, so while terse it is quite limited, functions are better in these regards
Thus, I would default to $state objects and functions instead of $derived when starting out; with these option there are actually no limitations except the lack of instance creation which again can be compensated with arrays; once more familiar with Runes you realize that you use $state primitives and $derived as terser and/or more expressive API more in components; but be aware that once you want to export them you face some significant refactoring effort; classes might have slightly better performance (untested), can have instances and embed $derived and hence, save the calling brackets () when accessing the value in contrast to a function but again have zero type hints which makes consuming them cumbersome
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Intro
There are actually multiple options of how to use $state and $derived with different implications. Following decision trees help narrowing down when to use which option. There is a summary at the bottom with default recommendations when starting out.
Its tl;dr is:
When starting out...
$state({ value: 0 })
or$state([0, 0])
or$state([{ value: 0 }])
() => someState
If you don't understand the terms in the decision trees you can find examples below the trees.
There are even more options than described but I limited the trees to those options you are going to use IRL and where high flexibility, less boilerplate and overall DX are key.
$state
Examples and docs for each option:
$state(0)
docs$state({ value: 0 })
docsclass Something { value = $state(0); d = $derived(this.value) }
docsYou get most features with
class
and the ability to create multiple instances but it has the most boilerplate and the most minimal type hints, actually none except the class name; $state primitive is pretty bare bone and needs to be refactored if you want more but it's lean and a $state object is somewhere in the middle with very slight performance overhead but gives you way better type hints than a class.You can still use $state objects when needing $derived, you just embed a function instead. Putting a $derived outside as a dedicated constant declaration doesn't always work because it can't be exported. So, with option 2 and you might rarely run into limitations and don't need to refactor while with option 1 things are much more limited. Option 2 seems to offer the most balanced package regarding features, flexibility, performance and DX.
Bonus tip: Always use arrow functions within classes, so
this
refers to the lexical scope or where the function was defined.Here the same info as a comparison chart:
*This is actually "State needs write access and to be exported" but since $state always needs some write access at some point (otherwise why would I use $state?) it is shortened to "State needs to be exported".
$derived/$derived.by
Examples:
const someDerivedState = $derived(someState)
export const someDerivedState = () => someState
orexport const objectState = { someDerivedState: () => someState }
class ClassWRunes { someDerivedState = $derived(someState) }; export const classWRunes = new ClassWithRunes()
Once you want to export a $derived you need to embed it into a class with Runes which again has the most boilerplate and no type hints. It is easier to just use a function which can be embedded into $state object or just left outside and still be exported, in contrast to $derived.
Summary
While Runes give quite some options how to work with them it can be overwhelming when you just get started. All options have their place but to reduce complexity and mental overhead, you should have one default option in your mind and deviate when appropriate:
Beta Was this translation helpful? Give feedback.
All reactions