Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

What's the recommended pattern to perform cleanup with runes?#11980

Unanswered
r-thomson asked this question inQ&A
Discussion options

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-updatingDate:

functionmakeClock(){letdate=$state(newDate());letinterval=setInterval(()=>{date=newDate();},1000);return{getdate(){returndate}};}

In this example, how could I callclearInterval() once this reactive state is no longer being observed?

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?

You must be logged in to vote

Replies: 3 comments 3 replies

Comment options

You can use$effect (which can return a cleanup function) and$effect.active to create the same logic.
An example shared by karimfromjordan on Discord:

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;}};}

REPL

You must be logged in to vote
3 replies
@gterras
Comment options

Ain't this a bit concerning that this looks like a dirty hack in itself, let alone compared to svelte4 implementation?

@brunnerh
Comment options

Well, maybe Svelte itself could be providing something like this as an export, since this is a bit low level/technical.

@anthumchris
Comment options

#16298 - Provide init/destroy callbacks to $state

Comment options

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 intocreateKeyedWatcher for portability. The subscribers are tracked per getter using the setup function as a key to track each getter.

Usage 1
exportfunctionmakeClock(){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 2
exportfunctionmakeClock(){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;},};}
Implementation
import{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);}});};});}},};}

Svelte REPL

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.

You must be logged in to vote
0 replies
Comment options

REPL example:$state init/destroy

This provides init/destroy callbacks to$state, similar to theStartStopNotifier used by a Sveltestore

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}
You must be logged in to vote
0 replies
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Category
Q&A
Labels
None yet
5 participants
@r-thomson@brunnerh@anthumchris@gterras@kwangure

[8]ページ先頭

©2009-2025 Movatter.jp