Skip to content

Reactivity & Lifecycle (Runes)

React organises reactivity into discrete hooks: useState, useMemo, useEffect, useRef, and more. Svelte 5 replaces all of them with a single unified primitive called runes — compiler-understood keywords prefixed with $. You do not call these like functions in the traditional sense; the compiler reads them at build time and generates optimised reactive code for you.

This module is the course centrepiece. Every subsequent lesson dives into one rune in depth. Start here to get the complete mental map before you dive in.

React hookSvelte 5 runeWhat it does
useState(init)$state(init)Reactive value — mutate directly, no setter needed
useMemo(() => expr, deps)$derived(expr)Computed value — auto-tracks dependencies, no deps array
useMemo(() => fn(), deps)$derived.by(() => fn())Computed value with a multi-step function body
useEffect(fn, deps)$effect(fn)Side-effect — auto-tracks its dependencies
useEffect(fn, [])onMount(fn)Run once after the component mounts
useEffect(() => () => cleanup, [])onDestroy(fn)Run once when the component is destroyed
useRef(init)plain let variable or bind:thisMutable ref that does not trigger re-renders
useContext(Ctx)getContext(key)Read context provided by an ancestor
Component props$props()Declare and destructure incoming props
Callback props / lifting state$bindable()Two-way bindable prop

The biggest conceptual shift: React hooks require an explicit dependency array. Svelte runes are tracked by the compiler — you never list dependencies manually.

React
function Counter() {
const [count, setCount] = React.useState(0);
const doubled = React.useMemo(() => count * 2, [count]);
React.useEffect(() => {
document.title = 'Count: ' + count;
}, [count]);
return (
<div>
<button onClick={() => setCount(c => c + 1)}>+1</button>
<p>Count: {count} — Doubled: {doubled}</p>
</div>
);
}
Svelte
<script>
let count = $state(0);
let doubled = $derived(count * 2);
$effect(() => {
document.title = 'Count: ' + count;
});
</script>
<button onclick={() => count++}>+1</button>
<p>Count: {count} — Doubled: {doubled}</p>

Three runes, zero dependency arrays. The compiler figures out that doubled depends on count, and that the $effect should re-run whenever count changes.

Which Svelte 5 rune replaces React's useState?
Why does $derived need no dependency array?
What is the Svelte 5 equivalent of useEffect with an empty deps array []?
What is the key difference between $derived and $derived.by?