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
To give a class a lazy property in JavaScript, we can do the following (quite verbose);
classLazyFoo{
#foo
#fooInit(){/* some expensive computation that may or may not be needed */}getfoo(){return(this.#foo ??=this.#fooInit())}setfoo(value){this.#foo =value}}
One mistake can cost a lot of debugging time if you're not careful, which is why an @lazy decorator can be so valuable.
A lazy reactive property requires all the same boilerplate;
classReactiveLazyFoo{
#fooImpl =$state()// we want `foo` to be writable, so we can't simply use `$derived.by`
#fooInit(){/* some expensive computation that may or may not be needed */}getfoo(){return(this.#fooImpl ??=this.#fooInit())}setfoo(value){this.#fooImpl =value}}
Describe the proposed solution
please note that I'm not well versed in Svelte's internals, so the compiler output samples below are just to get the general idea across, not to give concrete suggestions
import*as$from'svelte/internal/client';classReactiveWritableLazyFoo{
#foo =$.state();
#foo__initializer =()=>/* expensive */getfoo(){// if the init fn exists, call it, set foo, then clear the initializer (saves having a boolean flag, and after one call the function is no longer needed)this.#foo__initializer &&(this.#foo =this.#foo__initializer())return$.get(this.#foo);}setfoo(value){deletethis.#foo__initializer
$.set(this.#foo,value,true);}}
This wouldn't add to Svelte's internal runtime, instead being a compiler change to treat $state.lazy the same as $state, but with the additional field and the additional statements in the getter & setter.
In components (or just variables in general), the output would have to include notably more additional code than in .svelte.[js|ts], as there now needs to be some operation around the initializer on every $.get and $.set. It might be better to emulate the class behavior; create a getFoo and setFoo function which call $.get and $.set respectively, along with the operation on the initializer.
It may even be better to disallow $state.lazy outside of class fields entirely given the amount of additional work the compiler would have to do. That, and reactive values inside of components benefiting from laziness is much rarer than class fields.
In cases where it is desirable, a static class can be created, which is relatively inexpensive. Or, if it turns out to be cheaper than the alternatives, the compiler could inject a static class in place of some let foo = $state.lazy(...), though that doesn't seem ideal.
Importance
would make my life easier
The text was updated successfully, but these errors were encountered:
$derived is writable as of svelte 5.25, so you can actually use that now (provided the initialisation function doesn’t refer a state or another derived, otherwise it could rerun when those update)
Describe the problem
To give a class a lazy property in JavaScript, we can do the following (quite verbose);
One mistake can cost a lot of debugging time if you're not careful, which is why an
@lazy
decorator can be so valuable.A lazy reactive property requires all the same boilerplate;
Describe the proposed solution
please note that I'm not well versed in Svelte's internals, so the compiler output samples below are just to get the general idea across, not to give concrete suggestions
We could have
$state.lazy
;Which transpiles to;
This wouldn't add to Svelte's internal runtime, instead being a compiler change to treat
$state.lazy
the same as$state
, but with the additional field and the additional statements in the getter & setter.In components (or just variables in general), the output would have to include notably more additional code than in
.svelte.[js|ts]
, as there now needs to be some operation around the initializer on every$.get
and$.set
. It might be better to emulate the class behavior; create agetFoo
andsetFoo
function which call$.get
and$.set
respectively, along with the operation on the initializer.It may even be better to disallow
$state.lazy
outside of class fields entirely given the amount of additional work the compiler would have to do. That, and reactive values inside of components benefiting from laziness is much rarer than class fields.In cases where it is desirable, a static class can be created, which is relatively inexpensive. Or, if it turns out to be cheaper than the alternatives, the compiler could inject a static class in place of some
let foo = $state.lazy(...)
, though that doesn't seem ideal.Importance
would make my life easier
The text was updated successfully, but these errors were encountered: