Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork4.6k
-
I've been playing around with Svelte 5 by porting a project over, and one thing I'm not really seeing a good way to handle cleanup of side effects. For example, here's some runes code that creates a constantly-updating functionmakeClock(){letdate=$state(newDate());letinterval=setInterval(()=>{date=newDate();},1000);return{getdate(){returndate}};} In this example, how could I call For reference, here is how you could do this with stores: functionmakeClock(){letstore=writable(newDate(),(set)=>{letinterval=setInterval(()=>{set(newDate())},1000);return()=>clearInterval(interval)});returnreadonly(store);} I am aware stores are not going anywhere in Svelte 5. But is there a way to do this with runes, or is the word to keep using stores if you have side effects you need to manage? |
BetaWas this translation helpful?Give feedback.
All reactions
Replies: 3 comments 3 replies
-
You can use import{tick}from'svelte';exportdefaultfunctionreadable(initial_value,start){letvalue=$state(initial_value);letsubscribers=0;letstop=null;return{getvalue(){if($effect.active()){$effect(()=>{if(subscribers++===0){stop=start(fn=>value=fn(value));}return()=>{tick().then(()=>{if(--subscribers===0){stop?.();stop=null;}});};});}returnvalue;}};} |
BetaWas this translation helpful?Give feedback.
All reactions
😕 1
-
Ain't this a bit concerning that this looks like a dirty hack in itself, let alone compared to svelte4 implementation? |
BetaWas this translation helpful?Give feedback.
All reactions
👍 5
-
Well, maybe Svelte itself could be providing something like this as an export, since this is a bit low level/technical. |
BetaWas this translation helpful?Give feedback.
All reactions
👍 3
-
BetaWas this translation helpful?Give feedback.
All reactions
-
I've seen variants ofthe pattern linked by brunnerh cited as the go-to pattern in several PRs and issues. I've refactored it slightly into Usage 1exportfunctionmakeClock(){letdate1=$state(newDate());letdate2=$state(newDate());letdate3=$state(newDate());constsetupDate1=()=>{constintervalId=setInterval(()=>(date1=newDate()),1000);return()=>clearInterval(intervalId);};constsetupDate2=()=>{constintervalId=setInterval(()=>(date2=newDate()),2000);return()=>clearInterval(intervalId);};constsetupDate3=()=>{constintervalId=setInterval(()=>(date3=newDate()),3000);return()=>clearInterval(intervalId);};constwatcher=createKeyedWatcher();return{getdate1(){watcher.watch(setupDate1);returndate1;},getdate2(){watcher.watch(setupDate2);returndate2;},getdate3(){watcher.watch(setupDate3);returndate3;},};} Usage 2exportfunctionmakeClock(){letdate1=$state(newDate());letdate2=$state(newDate());letdate3=$state(newDate());constsharedSetup=()=>{constintervalId1=setInterval(()=>(date1=newDate()),1000);constintervalId2=setInterval(()=>(date2=newDate()),2000);constintervalId3=setInterval(()=>(date3=newDate()),3000);return()=>{clearInterval(intervalId1);clearInterval(intervalId2);clearInterval(intervalId3);};};constwatcher=createKeyedWatcher();return{getdate1(){watcher.watch(sharedSetup);returndate1;},getdate2(){watcher.watch(sharedSetup);returndate2;},getdate3(){watcher.watch(sharedSetup);returndate3;},};} Implementationimport{tick,untrack}from"svelte";functioncreateKeyedWatcher(){letwatchers=newMap();return{watch(setup){if($effect.tracking()){$effect(()=>{letentry=watchers.get(setup);if(!entry){constcleanup=untrack(setup);entry=[0,cleanup];watchers.set(setup,entry);}entry[0]++;return()=>{tick().then(()=>{entry[0]--;if(entry[0]===0){entry[1]?.();// Run cleanupwatchers.delete(setup);}});};});}},};} This variant works better for tracking properties of classes, for example. I put emphasis on the keyed-ness in the name to detract people creating a new function with each property access. This: return{getdate(){watcher.watch(()=>{constintervalId=setInterval(()=>(date=newDate()),1000);return()=>clearInterval(intervalId);});returndate;},}; ...is probably not what you want in most cases. |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
REPL example:$state init/destroy This provides init/destroy callbacks to import{createSubscriber}from'svelte/reactivity'exportfunctionst8(val,initDestroy){conststate=$state(val)if('function'==typeofinitDestroy){constsubscribe=createSubscriber(()=>initDestroy(state))returnnewProxy(state,{get(){subscribe()returnReflect.get(...arguments)},})}returnstate} |
BetaWas this translation helpful?Give feedback.