Basic Svelte
Introduction
Bindings
Classes and styles
Advanced Svelte
Advanced reactivity
Motion
Advanced bindings
Advanced transitions
Context API
Special elements
<script module>
Next steps
Basic SvelteKit
Introduction
Routing
Loading data
Headers and cookies
Shared modules
API routes
$app/state
Errors and redirects
Advanced SvelteKit
Page options
Link options
Advanced routing
Advanced loading
Environment variables
Conclusion
So far weβve talked about reactivity in terms of state. But thatβs only half of the equation β state is only reactive if something is reacting to it, otherwise itβs just a sparkling variable.
The thing that reacts is called an effect. Youβve already encountered effects β the ones that Svelte creates on your behalf to update the DOM in response to state changes β but you can also create your own with the $effect
rune.
Most of the time, you shouldnβt.
$effect
is best thought of as an escape hatch, rather than something to use frequently. If you can put your side effects in an event handler, for example, thatβs almost always preferable.
Letβs say we want to use setInterval
to keep track of how long the component has been mounted. Create the effect:
<script>
let elapsed = $state(0);
let interval = $state(1000);
$effect(() => {
setInterval(() => {
elapsed += 1;
}, interval);
});
</script>
<script lang="ts">
let elapsed = $state(0);
let interval = $state(1000);
$effect(() => {
setInterval(() => {
elapsed += 1;
}, interval);
});
</script>
Click the βspeed upβ button a few times and notice that elapsed
ticks up faster, because weβre calling setInterval
each time interval
gets smaller.
If we then click the βslow downβ button... well, it doesnβt work. Thatβs because weβre not clearing out the old intervals when the effect updates. We can fix that by returning a cleanup function:
$effect(() => {
const id = setInterval(() => {
elapsed += 1;
}, interval);
return () => {
clearInterval(id);
};
});
The cleanup function is called immediately before the effect function re-runs when interval
changes, and also when the component is destroyed.
If the effect function doesnβt read any state when it runs, it will only run once, when the component mounts.
Effects do not run during server-side rendering.
<script>
let elapsed = $state(0);
let interval = $state(1000);
</script>
<button onclick={() => interval /= 2}>speed up</button>
<button onclick={() => interval *= 2}>slow down</button>
<p>elapsed: {elapsed}</p>