🎭 Svelte Effects: Your App’s Automatic Helpers
The Magic Story of Effects
Imagine you have a magic helper who watches over your toys. Every time you move a toy, this helper automatically does something helpful—like turning on a light when you put a car in the garage, or playing music when you set a doll on the dance floor.
In Svelte, effects are these magic helpers. They watch your data and automatically do things when that data changes!
🌟 What Are Effects?
Think of your app like a house:
- State (
$state) = your stuff (toys, books, snacks) - Effects (
$effect) = automatic helpers that respond when stuff changes
let count = $state(0);
$effect(() => {
console.log('Count changed to:', count);
});
Every time count changes, the effect runs automatically!
📦 The $effect Rune
The $effect rune is your main helper. It runs after Svelte updates the screen.
Simple Example: A Light Switch
<script>
let isOn = $state(false);
$effect(() => {
if (isOn) {
document.title = '💡 Light ON';
} else {
document.title = '🌙 Light OFF';
}
});
</script>
<button onclick={() => isOn = !isOn}>
Toggle Light
</button>
What happens:
- You click the button
isOnchanges- Svelte updates the screen
- The effect runs and changes the page title
⚡ The $effect.pre Rune
Sometimes you need your helper to work before the screen updates. That’s $effect.pre!
The Story
Imagine you’re painting a wall.
$effect= takes a photo after you finish painting$effect.pre= prepares the camera before you start
When to Use It
Use $effect.pre when you need to:
- Measure something before it changes
- Save a scroll position
- Capture “before” values
<script>
let messages = $state([]);
let container;
let shouldScroll = false;
$effect.pre(() => {
// Check BEFORE new messages appear
if (container) {
const atBottom =
container.scrollTop +
container.clientHeight >=
container.scrollHeight - 10;
shouldScroll = atBottom;
}
});
$effect(() => {
// Scroll AFTER messages appear
if (shouldScroll && container) {
container.scrollTop =
container.scrollHeight;
}
});
</script>
🌳 The $effect.root Function
Normally, effects live inside your component. When the component disappears, effects stop automatically.
But what if you need an effect that lives outside a component? That’s $effect.root!
The Story
Think of a regular effect like a pet fish in a bowl. When you clean the bowl (component unmounts), the fish goes too.
$effect.root is like having a fish tank in the living room—it stays even when you leave your bedroom!
Example: A Shared Timer
<script>
import { createTimer } from './timer.js';
const timer = createTimer();
</script>
// timer.js
export function createTimer() {
let seconds = $state(0);
const cleanup = $effect.root(() => {
const interval = setInterval(() => {
seconds++;
}, 1000);
return () => clearInterval(interval);
});
return {
get seconds() { return seconds; },
stop: cleanup
};
}
Key Point: You must call cleanup() yourself when done!
🧹 Effect Cleanup
What if your effect starts something that needs to stop later? Like turning on a fan—you need to turn it off when you leave!
How Cleanup Works
Return a function from your effect. Svelte calls it:
- Before the effect runs again
- When the component is destroyed
<script>
let isActive = $state(true);
$effect(() => {
if (!isActive) return;
// Start something
const timer = setInterval(() => {
console.log('Tick!');
}, 1000);
// Cleanup function
return () => {
console.log('Cleaning up!');
clearInterval(timer);
};
});
</script>
Visual Flow
graph TD A[Effect Runs] --> B[Do Your Work] B --> C[Return Cleanup Function] C --> D{Data Changes?} D -->|Yes| E[Run Cleanup First] E --> A D -->|No| F{Component Destroyed?} F -->|Yes| G[Run Cleanup & Stop] F -->|No| D
🔗 Effect Dependencies
Effects are smart! They automatically know what data they use.
The Magic Detection
<script>
let name = $state('Alice');
let age = $state(10);
$effect(() => {
// Only uses 'name'
console.log('Hello', name);
});
// Runs when: name changes
// Ignores: age changes
</script>
How It Works
Svelte watches which $state values you read inside the effect. Only those become dependencies!
Be Careful!
// ❌ This won't track anything!
$effect(() => {
setTimeout(() => {
console.log(count); // Read inside timeout
}, 1000);
});
// ✅ This tracks correctly!
$effect(() => {
const current = count; // Read immediately
setTimeout(() => {
console.log(current);
}, 1000);
});
Rule: Read your reactive values at the top of your effect, not inside callbacks!
🔍 The $inspect Rune
Want to spy on your data? $inspect is your detective tool!
Basic Usage
<script>
let user = $state({ name: 'Bob' });
$inspect(user);
// Logs whenever user changes!
</script>
The .with() Method
Want custom logging?
<script>
let score = $state(0);
$inspect(score).with((type, value) => {
if (type === 'update') {
console.log('🎯 Score is now:', value);
}
});
</script>
Types of Changes
'init'= first time the value is set'update'= value changed after that
Pro Tip: Debugging Made Easy
<script>
let items = $state([]);
// Pause debugger when items change
$inspect(items).with(() => {
debugger;
});
</script>
🎯 Quick Comparison
| Rune | When It Runs | Use Case |
|---|---|---|
$effect |
After DOM updates | Most effects |
$effect.pre |
Before DOM updates | Measure/capture |
$effect.root |
Manual control | Outside components |
$inspect |
On any change | Debugging |
🌈 Real-World Example
Let’s build a Dark Mode Toggle with all our knowledge!
<script>
let isDark = $state(false);
// Debug mode changes
$inspect(isDark);
// Apply theme after render
$effect(() => {
document.body.classList.toggle(
'dark-mode',
isDark
);
// Save preference
localStorage.setItem(
'theme',
isDark ? 'dark' : 'light'
);
// Cleanup: restore original
return () => {
document.body.classList
.remove('dark-mode');
};
});
</script>
<button onclick={() => isDark = !isDark}>
{isDark ? '☀️ Light' : '🌙 Dark'}
</button>
🎉 You Did It!
You now understand Svelte’s effect system:
- ✅
$effect— runs after screen updates - ✅
$effect.pre— runs before screen updates - ✅
$effect.root— manual lifecycle control - ✅ Cleanup — return a function to clean up
- ✅ Dependencies — auto-detected from reads
- ✅
$inspect— debugging helper
Remember: Effects are your automatic helpers. Tell them what to watch, and they’ll do the work!
