Cours Svelte et SvelteKit · Module 3: Réactivité et Runes
$state - État réactif
Dans cette leçon5
$state est la rune la plus puissante : elle crée un état réactif qui met automatiquement à jour l'interface lors des changements.
Utilisation de base
<script>
// Nombre
let gold = $state(0);
// Chaîne de caractères
let vikingName = $state('Ragnar');
// Booléen
let isReady = $state(false);
// Tableau
let warriors = $state(['Bjorn', 'Ivar']);
// Objet
let ship = $state({
name: 'Drakkar',
crew: 50,
cargo: []
});
</script>Mettre à jour l'état
<script>
let count = $state(0);
let items = $state(['a', 'b']);
let user = $state({ name: 'Viking', level: 1 });
function examples() {
// Nombres - comme une assignation classique
count += 1;
count = count * 2;
// Tableaux - les mutations fonctionnent !
items.push('c'); // Fonctionne en Svelte 5 !
items[0] = 'x'; // Fonctionne !
items = [...items, 'd']; // Fonctionne aussi
// Objets - les mutations fonctionnent !
user.level += 1; // Fonctionne !
user.name = 'Jarl'; // Fonctionne !
}
</script>Réactivité profonde
$state crée un objet profondément réactif :
<script>
let kingdom = $state({
name: 'Nordheim',
villages: [
{ name: 'Svenheim', population: 500 },
{ name: 'Bjornvik', population: 300 }
]
});
function growVillage() {
// Mutation imbriquée - fonctionne automatiquement !
kingdom.villages[0].population += 100;
}
</script>
<p>{kingdom.villages[0].name}: {kingdom.villages[0].population}</p>
<button onclick={growVillage}>Grow village</button>$state avec les classes
<script>
class Warrior {
name = $state('');
health = $state(100);
weapon = $state('Sword');
constructor(name) {
this.name = name;
}
takeDamage(amount) {
this.health -= amount;
}
}
let hero = new Warrior('Ragnar');
</script>
<p>{hero.name}: {hero.health} HP</p>
<button onclick={() => hero.takeDamage(10)}>
Deal damage
</button>$state.raw - Sans réactivité profonde
Parfois, tu n'as pas besoin de réactivité profonde :
<script>
// Seule la référence est réactive, pas le contenu
let battleLog = $state.raw([
{ year: 793, place: 'Lindisfarne' },
{ year: 845, place: 'Paris' }
]);
// battleLog.push(...) ne rafraîchira PAS la vue - affecte un nouveau tableau
function addBattle() {
battleLog = [...battleLog, { year: 866, place: 'York' }];
}
</script>
<p>Batailles dans la chronique : {battleLog.length}</p>
<button onclick={addBattle}>Ajouter une bataille</button>Utilise $state.raw pour :
- De grands ensembles de données
- Des données en lecture seule
- L'optimisation des performances
Code de cette leçon : App.svelte
<script>
// $state - deep reactivity
let warrior = $state({
name: 'Ragnar',
stats: {
health: 100,
strength: 95,
energy: 80
},
inventory: ['Axe', 'Shield']
});
function takeDamage() {
// Nested mutations work!
warrior.stats.health -= 10;
}
function heal() {
warrior.stats.health = Math.min(100, warrior.stats.health + 20);
}
function addItem(item) {
warrior.inventory.push(item);
}
</script>
<main class="warrior-panel">
<h1>{warrior.name}</h1>
<section class="stats">
<h2>Stats</h2>
<div class="stat">
<span class="stat-label">Health</span>
<div class="bar">
<div class="fill health" style="width: {warrior.stats.health}%"></div>
</div>
<span>{warrior.stats.health}/100</span>
</div>
<div class="stat">
<span class="stat-label">Strength</span>
<div class="bar">
<div class="fill strength" style="width: {warrior.stats.strength}%"></div>
</div>
<span>{warrior.stats.strength}/100</span>
</div>
<div class="actions">
<button onclick={takeDamage} class="damage">Take damage</button>
<button onclick={heal} class="heal">Heal</button>
</div>
</section>
<section class="inventory">
<h2>Inventory ({warrior.inventory.length})</h2>
<ul>
{#each warrior.inventory as item}
<li>{item}</li>
{/each}
</ul>
<button onclick={() => addItem('Sword')}>+ Add Sword</button>
</section>
</main>
<style>
.warrior-panel {
font-family: 'Georgia', serif;
max-width: 500px;
margin: 0 auto;
padding: 2rem;
background: #1a0f0a;
color: #e8d5b7;
min-height: 100vh;
}
h1 {
color: #d4af37;
text-align: center;
}
h2 {
color: #d4af37;
font-size: 1rem;
margin-bottom: 1rem;
}
section {
background: rgba(212, 175, 55, 0.1);
border: 1px solid #d4af37;
border-radius: 8px;
padding: 1rem;
margin-bottom: 1rem;
}
.stat {
margin-bottom: 0.75rem;
}
.stat .stat-label {
display: block;
margin-bottom: 0.25rem;
}
.bar {
height: 20px;
background: rgba(0,0,0,0.5);
border-radius: 4px;
overflow: hidden;
}
.fill {
height: 100%;
transition: width 0.3s;
}
.fill.health { background: linear-gradient(90deg, #8b0000, #ff4444); }
.fill.strength { background: linear-gradient(90deg, #d4af37, #ffd700); }
.actions {
display: flex;
gap: 0.5rem;
margin-top: 1rem;
}
button {
flex: 1;
padding: 0.5rem;
border: none;
border-radius: 4px;
cursor: pointer;
color: white;
}
.damage { background: #8b0000; }
.heal { background: #2d5016; }
ul {
list-style: none;
padding: 0;
}
li {
padding: 0.5rem;
background: rgba(0,0,0,0.3);
margin: 0.25rem 0;
border-radius: 4px;
}
</style>Entrées de la documentation utilisées dans cette leçon
Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Comment créer un état réactif dans Svelte 5 ?
2. Qu'est-ce qui est vrai à propos de $state dans Svelte 5 ?
Tâches pratiques dans le jeu
- Éditeur de code
Complète le code en créant un tableau réactif de guerriers