Movatterモバイル変換


[0]ホーム

URL:


Skip to main content
SvelteRunes

$effect

Effects are functions that run when state updates, and can be used for things like calling third-party libraries, drawing on<canvas> elements, or making network requests. They only run in the browser, not during server-side rendering.

Generally speaking, you shouldnot update state inside effects, as it will make code more convoluted and will often lead to never-ending update cycles. If you find yourself doing so, seewhen not to use$effect to learn about alternative approaches.

You can create an effect with the$effect rune (demo):

<script>letsize=$state(50);letcolor=$state('#ff3e00');letcanvas;$effect(()=>{constcontext=canvas.getContext('2d');context.clearRect(0,0,canvas.width,canvas.height);// this will re-run whenever `color` or `size` changecontext.fillStyle=color;context.fillRect(0,0,size,size);});</script><canvasbind:this={canvas}width="100"height="100"></canvas>

When Svelte runs an effect function, it tracks which pieces of state (and derived state) are accessed (unless accessed insideuntrack), and re-runs the function when that state later changes.

If you’re having difficulty understanding why your$effect is rerunning or is not running seeunderstanding dependencies. Effects are triggered differently than the$: blocks you may be used to if coming from Svelte 4.

Understanding lifecycle

Your effects run after the component has been mounted to the DOM, and in amicrotask after state changes. Re-runs are batched (i.e. changingcolor andsize in the same moment won’t cause two separate runs), and happen after any DOM updates have been applied.

You can use$effect anywhere, not just at the top level of a component, as long as it is called while a parent effect is running.

Svelte uses effects internally to represent logic and expressions in your template — this is how<h1>hello {name}!</h1> updates whenname changes.

An effect can return ateardown function which will run immediately before the effect re-runs (demo).

<script>letcount=$state(0);letmilliseconds=$state(1000);$effect(()=>{// This will be recreated whenever `milliseconds` changesconstinterval=setInterval(()=>{count+=1;},milliseconds);return()=>{// if a teardown function is provided, it will run// a) immediately before the effect re-runs// b) when the component is destroyedclearInterval(interval);};});</script><h1>{count}</h1><buttononclick={()=>(milliseconds*=2)}>slower</button><buttononclick={()=>(milliseconds/=2)}>faster</button>

Teardown functions also run when the effect is destroyed, which happens when its parent is destroyed (for example, a component is unmounted) or the parent effect re-runs.

Understanding dependencies

$effect automatically picks up any reactive values ($state,$derived,$props) that aresynchronously read inside its function body (including indirectly, via function calls) and registers them as dependencies. When those dependencies change, the$effect schedules a re-run.

If$state and$derived are used directly inside the$effect (for example, during creation of areactive class), those values willnot be treated as dependencies.

Values that are readasynchronously — after anawait or inside asetTimeout, for example — will not be tracked. Here, the canvas will be repainted whencolor changes, but not whensize changes (demo):

function$effect(fn:()=>void|(()=>void)):voidnamespace$effect

Runs code when a component is mounted to the DOM, and then whenever its dependencies change, i.e.$state or$derived values.The timing of the execution is after the DOM has been updated.

Example:

$effect(()=>console.log('The count is now '+count));

If you return a function from the effect, it will be called right before the effect is run again, or when the component is unmounted.

Does not run during server side rendering.

https://svelte.dev/docs/svelte/$effect

@paramfn The function to execute
$effect
(()=>{
constconstcontext:CanvasRenderingContext2Dcontext=
letcanvas:{width:number;height:number;getContext(type:"2d",options?:CanvasRenderingContext2DSettings):CanvasRenderingContext2D;}
canvas
.functiongetContext(type:"2d",options?:CanvasRenderingContext2DSettings):CanvasRenderingContext2DgetContext('2d');
constcontext:CanvasRenderingContext2Dcontext.CanvasRect.clearRect(x: number,y: number,w: number,h: number):voidclearRect(0,0,
letcanvas:{width:number;height:number;getContext(type:"2d",options?:CanvasRenderingContext2DSettings):CanvasRenderingContext2D;}
canvas
.width:numberwidth,
letcanvas:{width:number;height:number;getContext(type:"2d",options?:CanvasRenderingContext2DSettings):CanvasRenderingContext2D;}
canvas
.height:numberheight);
// this will re-run whenever `color` changes...constcontext:CanvasRenderingContext2Dcontext.CanvasFillStrokeStyles.fillStyle: string|CanvasGradient|CanvasPatternfillStyle=letcolor:stringcolor;functionsetTimeout<[]>(callback:()=>void,delay?:number):NodeJS.Timeout(+2overloads)

Schedules execution of a one-timecallback afterdelay milliseconds.

Thecallback will likely not be invoked in preciselydelay milliseconds.Node.js makes no guarantees about the exact timing of when callbacks will fire,nor of their ordering. The callback will be called as close as possible to thetime specified.

Whendelay is larger than2147483647 or less than1 orNaN, thedelaywill be set to1. Non-integer delays are truncated to an integer.

Ifcallback is not a function, aTypeError will be thrown.

This method has a custom variant for promises that is available usingtimersPromises.setTimeout().

@sincev0.0.1
@paramcallback The function to call when the timer elapses.
@paramdelay The number of milliseconds to wait before calling thecallback.Default:1.
@paramargs Optional arguments to pass when thecallback is called.
@returnsfor use withclearTimeout()
setTimeout
(()=>{
// ...but not when `size` changesconstcontext:CanvasRenderingContext2Dcontext.CanvasRect.fillRect(x: number,y: number,w: number,h: number):voidfillRect(0,0,letsize:numbersize,letsize:numbersize);},0);});

An effect only reruns when the object it reads changes, not when a property inside it changes. (If you want to observe changesinside an object at dev time, you can use$inspect.)

<script>letstate=$state({ value:0});letderived=$derived({ value:state.value*2});// this will run once, because `state` is never reassigned (only mutated)$effect(()=>{state;});// this will run whenever `state.value` changes...$effect(()=>{state.value;});// ...and so will this, because `derived` is a new object each time$effect(()=>{derived;});</script><buttononclick={()=>(state.value+=1)}>{state.value}</button><p>{state.value} doubled is {derived.value}</p>

An effect only depends on the values that it read the last time it ran. This has interesting implications for effects that have conditional code.

For instance, ifcondition istrue in the code snippet below, the code inside theif block will run andcolor will be evaluated. As such, changes to eithercondition orcolorwill cause the effect to re-run.

Conversely, ifcondition isfalse,color will not be evaluated, and the effect willonly re-run again whencondition changes.

importfunctionconfetti(opts?:ConfettiOptions):voidconfettifrom'canvas-confetti';letletcondition:booleancondition=
function$state<true>(initial:true):true(+1overload)namespace$state

Declares reactive state.

Example:

letcount=$state(0);

https://svelte.dev/docs/svelte/$state

@paraminitial The initial value
$state
(true);
letletcolor:stringcolor=
function$state<"#ff3e00">(initial:"#ff3e00"):"#ff3e00"(+1overload)namespace$state

Declares reactive state.

Example:

letcount=$state(0);

https://svelte.dev/docs/svelte/$state

@paraminitial The initial value
$state
('#ff3e00');
function$effect(fn:()=>void|(()=>void)):voidnamespace$effect

Runs code when a component is mounted to the DOM, and then whenever its dependencies change, i.e.$state or$derived values.The timing of the execution is after the DOM has been updated.

Example:

$effect(()=>console.log('The count is now '+count));

If you return a function from the effect, it will be called right before the effect is run again, or when the component is unmounted.

Does not run during server side rendering.

https://svelte.dev/docs/svelte/$effect

@paramfn The function to execute
$effect
(()=>{
if(letcondition:truecondition) {functionconfetti(opts?:ConfettiOptions):voidconfetti({ConfettiOptions.colors: string[]colors:[letcolor:stringcolor] });}else{functionconfetti(opts?:ConfettiOptions):voidconfetti();}});

$effect.pre

In rare cases, you may need to run codebefore the DOM updates. For this we can use the$effect.pre rune:

<script>import{ tick }from'svelte';letdiv=$state();letmessages=$state([]);// ...$effect.pre(()=>{if(!div)return;// not yet mounted// reference `messages` array length so that this code re-runs whenever it changesmessages.length;// autoscroll when new messages are addedif(div.offsetHeight+div.scrollTop>div.scrollHeight-20) {tick().then(()=>{div.scrollTo(0,div.scrollHeight);});}});</script><divbind:this={div}>{#eachmessagesasmessage}<p>{message}</p>{/each}</div>

Apart from the timing,$effect.pre works exactly like$effect.

$effect.tracking

The$effect.tracking rune is an advanced feature that tells you whether or not the code is running inside a tracking context, such as an effect or inside your template (demo):

<script>console.log('in component setup:',$effect.tracking());// false$effect(()=>{console.log('in effect:',$effect.tracking());// true});</script><p>in template: {$effect.tracking()}</p><!-- true -->

It is used to implement abstractions likecreateSubscriber, which will create listeners to update reactive values butonly if those values are being tracked (rather than, for example, read inside an event handler).

$effect.pending

When usingawait in components, the$effect.pending() rune tells you how many promises are pending in the currentboundary, not including child boundaries (demo):

<buttononclick={()=>a++}>a++</button><buttononclick={()=>b++}>b++</button><p>{a} + {b} = {awaitadd(a,b)}</p>{#if$effect.pending()}<p>pending promises: {$effect.pending()}</p>{/if}

$effect.root

The$effect.root rune is an advanced feature that creates a non-tracked scope that doesn’t auto-cleanup. This is useful for nested effects that you want to manually control. This rune also allows for the creation of effects outside of the component initialisation phase.

constconstdestroy:()=>voiddestroy=
namespace$effectfunction$effect(fn:()=>void|(()=>void)):void

Runs code when a component is mounted to the DOM, and then whenever its dependencies change, i.e.$state or$derived values.The timing of the execution is after the DOM has been updated.

Example:

$effect(()=>console.log('The count is now '+count));

If you return a function from the effect, it will be called right before the effect is run again, or when the component is unmounted.

Does not run during server side rendering.

https://svelte.dev/docs/svelte/$effect

@paramfn The function to execute
$effect
.function$effect.root(fn:()=>void|(()=>void)):()=>void

The$effect.root rune is an advanced feature that creates a non-tracked scope that doesn’t auto-cleanup. This is useful fornested effects that you want to manually control. This rune also allows for creation of effects outside of the componentinitialisation phase.

Example:

&#x3C;script>let count = $state(0);const cleanup = $effect.root(() => {$effect(()=>{console.log(count);})return()=>{console.log('effect root cleanup');}});&#x3C;/script>&#x3C;button onclick={()=>cleanup()}>cleanup&#x3C;/button>

https://svelte.dev/docs/svelte/$effect#$effect.root

root
(()=>{
function$effect(fn:()=>void|(()=>void)):voidnamespace$effect

Runs code when a component is mounted to the DOM, and then whenever its dependencies change, i.e.$state or$derived values.The timing of the execution is after the DOM has been updated.

Example:

$effect(()=>console.log('The count is now '+count));

If you return a function from the effect, it will be called right before the effect is run again, or when the component is unmounted.

Does not run during server side rendering.

https://svelte.dev/docs/svelte/$effect

@paramfn The function to execute
$effect
(()=>{
// setup});return()=>{// cleanup};});// later...constdestroy:()=>voiddestroy();

When not to use $effect

In general,$effect is best considered something of an escape hatch — useful for things like analytics and direct DOM manipulation — rather than a tool you should use frequently. In particular, avoid using it to synchronise state. Instead of this...

<script>letcount=$state(0);letdoubled=$state();// don't do this!$effect(()=>{doubled=count*2;});</script>

...do this:

<script>letcount=$state(0);letdoubled=$derived(count*2);</script>

For things that are more complicated than a simple expression likecount * 2, you can also use$derived.by.

If you’re using an effect because you want to be able to reassign the derived value (to build an optimistic UI, for example) note thatderiveds can be directly overridden as of Svelte 5.25.

You might be tempted to do something convoluted with effects to link one value to another. The following example shows two inputs for “money spent” and “money left” that are connected to each other. If you update one, the other should update accordingly. Don’t use effects for this (demo):

<script>consttotal=100;letspent=$state(0);letleft=$state(total);$effect(()=>{left=total-spent;});$effect(()=>{spent=total-left;});</script><label><inputtype="range"bind:value={spent}max={total} />{spent}/{total} spent</label><label><inputtype="range"bind:value={left}max={total} />{left}/{total} left</label>

Instead, useoninput callbacks or — better still —function bindings where possible (demo):

<script>consttotal=100;letspent=$state(0);letleft=$derived(total-spent);functionupdateLeft(left) {spent=total-left;}</script><label><inputtype="range"bind:value={spent}max={total} />{spent}/{total} spent</label><label><inputtype="range"bind:value={()=>left,updateLeft}max={total} />{left}/{total} left</label>

If you absolutely have to update$state within an effect and run into an infinite loop because you read and write to the same$state, useuntrack.

Edit this page on GitHub llms.txt

previousnext

[8]ページ先頭

©2009-2025 Movatter.jp