🎭 Svelte Reactivity: The Magic Notebook
The Story of the Magic Notebook 📔
Imagine you have a magic notebook. When you write a number on one page, other pages that depend on that number automatically update themselves. You don’t have to erase and rewrite—the notebook does it for you!
That’s exactly what Svelte’s reactivity system does for your code.
🌟 Chapter 1: Declaring Variables (The Old Way)
Before we discover the magic, let’s see the ordinary way to store information.
What is a Variable?
Think of a variable like a labeled box. You put something inside, and the label tells you what’s in it.
let name = "Alex";
let age = 10;
let favoriteColor = "blue";
Simple Example:
nameis a box labeled “name” with “Alex” insideageis a box labeled “age” with 10 inside- You can change what’s inside anytime!
age = 11; // Happy Birthday! 🎂
The Problem: In regular JavaScript, if something else depends on age, it won’t know the box changed. You’d have to manually tell everything to update.
✨ Chapter 2: The $state Rune (Your Magic Wand)
What is a Rune?
A rune is like a magic spell word. In Svelte 5, runes start with $ and give your variables superpowers!
The $state Rune
$state turns an ordinary box into a magic box that tells everyone when something changes!
<script>
let count = $state(0);
</script>
<button onclick={() => count++}>
Clicked {count} times
</button>
What happens:
countstarts at 0- When you click,
countbecomes 1 - The screen automatically shows “Clicked 1 times”
- No manual updates needed! ✨
Before vs After
Without $state |
With $state |
|---|---|
let count = 0 |
let count = $state(0) |
| Screen stays frozen | Screen updates automatically |
| You do all the work | Svelte does the work for you |
🧊 Chapter 3: $state.raw (The Frozen Box)
When You Don’t Need Magic
Sometimes you have big data that doesn’t need to update piece by piece. It only changes all at once.
Think of it like a frozen pizza 🍕—you don’t change one topping at a time. You swap the whole pizza!
<script>
let bigData = $state.raw([
{ id: 1, name: "Item 1" },
{ id: 2, name: "Item 2" }
]);
function replaceAll() {
// Swap the entire list
bigData = [
{ id: 3, name: "New Item" }
];
}
</script>
When to use $state.raw:
- ✅ Large lists that replace entirely
- ✅ Data from a server (arrives complete)
- ❌ Not for data you edit piece by piece
Why use it? It’s faster because Svelte doesn’t watch every tiny piece.
📚 Chapter 4: Reactive Arrays (Magic Lists)
Arrays are like lists of things. With $state, your lists become magic lists!
Creating a Reactive Array
<script>
let fruits = $state(["apple", "banana"]);
</script>
<ul>
{#each fruits as fruit}
<li>{fruit}</li>
{/each}
</ul>
<button onclick={() => fruits.push("orange")}>
Add Orange 🍊
</button>
What happens when you click:
- “orange” gets added to the list
- Screen instantly shows the new fruit
- Magic! 🪄
Array Methods That Work
fruits.push("grape"); // Add to end
fruits.pop(); // Remove last
fruits.shift(); // Remove first
fruits[0] = "mango"; // Replace first
All these trigger updates automatically!
🏠 Chapter 5: Reactive Objects (Magic Folders)
Objects are like folders with labeled pockets. Each pocket has a name and holds something.
Creating a Reactive Object
<script>
let person = $state({
name: "Sam",
age: 8,
hobby: "drawing"
});
</script>
<p>Name: {person.name}</p>
<p>Age: {person.age}</p>
<button onclick={() => person.age++}>
Birthday! 🎂
</button>
What happens:
- Click the button
person.agegoes from 8 to 9- The screen updates instantly!
Adding New Pockets
person.favoriteFood = "pizza";
// Screen updates to show the new info!
🌊 Chapter 6: Deep Reactivity (Magic All the Way Down)
What is Deep Reactivity?
Imagine a Russian nesting doll 🪆. There’s a doll inside a doll inside a doll.
Deep reactivity means Svelte’s magic works at EVERY level—even the smallest doll inside!
<script>
let school = $state({
name: "Sunny School",
classes: [
{
name: "Art",
students: ["Amy", "Bob"]
}
]
});
</script>
<p>First class: {school.classes[0].name}</p>
<button onclick={() => {
school.classes[0].students.push("Charlie");
}}>
Add Student
</button>
The magic reaches:
school✅school.classes✅school.classes[0]✅school.classes[0].students✅
Every level updates the screen when changed!
graph TD A[school] --> B[name: Sunny School] A --> C[classes] C --> D[Class 0] D --> E[name: Art] D --> F[students] F --> G[Amy] F --> H[Bob] F --> I[Charlie ✨ new!]
🔮 Chapter 7: The $derived Rune (Automatic Calculations)
The Magic Calculator
What if one value depends on another? Like:
“My birth year = Current year - My age”
With $derived, Svelte calculates it automatically whenever the source changes!
<script>
let price = $state(100);
let quantity = $state(2);
let total = $derived(price * quantity);
</script>
<p>Price: ${price}</p>
<p>Quantity: {quantity}</p>
<p>Total: ${total}</p>
<button onclick={() => quantity++}>
Add One More
</button>
What happens:
- Start: price=100, quantity=2, total=200
- Click button: quantity becomes 3
totalautomatically becomes 300!
Key Rules
| Rule | Explanation |
|---|---|
| Read-only | You can’t set total = 500 directly |
| Auto-updates | Changes when source values change |
| Simple formula | Best for one-line calculations |
🧙♂️ Chapter 8: The $derived.by Rune (Complex Magic)
When Simple Isn’t Enough
Sometimes your calculation needs multiple steps. That’s when $derived.by comes in!
Think of it like a recipe 📝—you need several steps to make the final dish.
<script>
let items = $state([
{ name: "Apple", price: 2 },
{ name: "Bread", price: 3 },
{ name: "Milk", price: 4 }
]);
let summary = $derived.by(() => {
let total = 0;
let count = items.length;
for (let item of items) {
total += item.price;
}
return {
itemCount: count,
totalPrice: total,
average: total / count
};
});
</script>
<p>Items: {summary.itemCount}</p>
<p>Total: ${summary.totalPrice}</p>
<p>Average: ${summary.average.toFixed(2)}</p>
$derived vs $derived.by
$derived |
$derived.by |
|---|---|
| One-line formula | Multi-step logic |
$derived(a + b) |
$derived.by(() => { ... }) |
| Quick calculations | Complex transformations |
// Simple: use $derived
let doubled = $derived(count * 2);
// Complex: use $derived.by
let stats = $derived.by(() => {
// Step 1: Filter
let valid = items.filter(i => i.active);
// Step 2: Calculate
let sum = valid.reduce((a, b) => a + b.value, 0);
// Step 3: Return result
return { count: valid.length, sum };
});
🎯 The Complete Picture
graph TD A[$state] --> B[Basic reactive value] A --> C[$state.raw] C --> D[Fast, replace-only] E[$derived] --> F[Auto-calculated value] E --> G[$derived.by] G --> H[Complex calculations] B --> I[Arrays] B --> J[Objects] I --> K[Deep Reactivity] J --> K
🌈 Summary: Your Reactivity Toolkit
| Tool | When to Use | Example |
|---|---|---|
$state(value) |
Any reactive data | let count = $state(0) |
$state.raw(value) |
Big data, full replacement | let data = $state.raw([...]) |
$derived(expr) |
Simple calculations | let double = $derived(n * 2) |
$derived.by(fn) |
Complex logic | let result = $derived.by(() => {...}) |
🚀 You Did It!
You now understand Svelte’s reactivity system! Remember:
$statemakes values reactive$state.rawis for big, swap-all-at-once data- Arrays and Objects inside
$stateare deeply reactive $derivedcalculates values automatically$derived.byhandles complex multi-step calculations
Like a magic notebook, your Svelte app now updates itself whenever something changes. No manual work needed! ✨
