Cours Vue.js · Module 11: Pinia

Le State dans Pinia

3 min de lecture
Dans cette leçon5

Le state, ce sont les données réactives stockées dans le store - comme la base de données de l'ordinateur principal au NOVA LAB. Chaque relevé de capteur, chaque paramètre de mission y est enregistré et disponible pour tous les modules de la station.

Définir le state

En style Composition API, le state se résume à ref() et reactive() :

1import { defineStore } from 'pinia'
2import { ref, reactive } from 'vue'
3
4export const useResourceStore = defineStore('resources', () => {
5  // Valeurs simples - ref()
6  const oxygen = ref(98.5)
7  const water = ref(1250)
8  const energy = ref(87)
9  const isEmergency = ref(false)
10
11  // Objets - reactive() ou ref()
12  const crew = reactive({
13    commander: 'Nova',
14    engineer: 'Atlas',
15    scientist: 'Darwin'
16  })
17
18  // Tableaux
19  const logs = ref([])
20
21  return { oxygen, water, energy, isEmergency, crew, logs }
22})

Modifier le state

Le state peut être modifié directement dans les actions ou depuis un composant :

1export const useResourceStore = defineStore('resources', () => {
2  const oxygen = ref(98.5)
3
4  // L'action modifie le state
5  function consumeOxygen(amount) {
6    oxygen.value = Math.max(0, oxygen.value - amount)
7  }
8
9  return { oxygen, consumeOxygen }
10})
1<script setup>
2const store = useResourceStore()
3
4// Modification directe (ça marche, mais les actions sont préférables)
5store.oxygen = 95.0
6
7// Via une action (recommandé)
8store.consumeOxygen(3.5)
9</script>

$patch - mettre à jour plusieurs propriétés

$patch permet de mettre à jour plusieurs propriétés du state en une seule fois - plus efficace que de les modifier une par une :

1const store = useResourceStore()
2
3// Patch par objet - simple remplacement
4store.$patch({
5  oxygen: 95.0,
6  water: 1200,
7  energy: 82,
8  isEmergency: false
9})
10
11// Patch par fonction - pour les opérations complexes
12store.$patch((state) => {
13  state.oxygen -= 3.5
14  state.logs.push({
15    type: 'consumption',
16    timestamp: Date.now()
17  })
18})

$reset - restaurer l'état initial

En style Options API, $reset() fonctionne automatiquement. En Composition API, tu dois définir ta propre fonction de reset :

1export const useResourceStore = defineStore('resources', () => {
2  const oxygen = ref(100)
3  const water = ref(1500)
4  const energy = ref(100)
5
6  // Reset personnalisé pour la Composition API
7  function $reset() {
8    oxygen.value = 100
9    water.value = 1500
10    energy.value = 100
11  }
12
13  return { oxygen, water, energy, $reset }
14})
15
16// Utilisation
17const store = useResourceStore()
18store.$reset() // Restaure les valeurs initiales

$state - accéder à l'état complet

1const store = useResourceStore()
2
3// Lire tout le state
4const snapshot = store.$state
5
6// Remplacer tout le state
7store.$state = {
8  oxygen: 100,
9  water: 1500,
10  energy: 100,
11  isEmergency: false,
12  crew: { commander: 'Nova' },
13  logs: []
14}
Code de cette leçon : App.vue
1<script setup>
2import { ref, computed } from 'vue'
3
4// Simulation d'un Resource Store
5const oxygen = ref(98.5)
6const water = ref(1250)
7const energy = ref(87)
8const logs = ref([])
9
10// Getters
11const oxygenStatus = computed(() => oxygen.value > 50 ? 'OK' : 'LOW')
12const waterStatus = computed(() => water.value > 500 ? 'OK' : 'LOW')
13const energyStatus = computed(() => energy.value > 40 ? 'OK' : 'LOW')
14
15// Actions
16function consumeOxygen(amount) {
17  oxygen.value = Math.max(0, +(oxygen.value - amount).toFixed(1))
18  addLog('Oxygen consumed: -' + amount + '%')
19}
20
21function consumeWater(amount) {
22  water.value = Math.max(0, water.value - amount)
23  addLog('Water consumed: -' + amount + 'L')
24}
25
26function consumeEnergy(amount) {
27  energy.value = Math.max(0, energy.value - amount)
28  addLog('Energy consumed: -' + amount + '%')
29}
30
31function addLog(message) {
32  logs.value.unshift({
33    message,
34    time: new Date().toLocaleTimeString()
35  })
36  if (logs.value.length > 8) logs.value.pop()
37}
38
39// Simulation de $patch
40function patchResources(updates) {
41  if (updates.oxygen !== undefined) oxygen.value = updates.oxygen
42  if (updates.water !== undefined) water.value = updates.water
43  if (updates.energy !== undefined) energy.value = updates.energy
44  addLog('Resources patched')
45}
46
47function resetResources() {
48  oxygen.value = 100
49  water.value = 1500
50  energy.value = 100
51  logs.value = []
52}
53</script>
54
55<template>
56  <div class="nova-lab">
57    <h1>NOVA LAB - State Management</h1>
58
59    <div class="grid">
60      <div class="resource-panel">
61        <h2>Resources</h2>
62        <div class="resource" v-for="r in [
63          { name: 'Oxygen', value: oxygen, unit: '%', status: oxygenStatus, action: () => consumeOxygen(5) },
64          { name: 'Water', value: water, unit: 'L', status: waterStatus, action: () => consumeWater(50) },
65          { name: 'Energy', value: energy, unit: '%', status: energyStatus, action: () => consumeEnergy(10) }
66        ]" :key="r.name">
67          <div class="r-header">
68            <span>{{ r.name }}</span>
69            <span :class="r.status.toLowerCase()">{{ r.status }}</span>
70          </div>
71          <div class="r-value">{{ r.value }}{{ r.unit }}</div>
72          <button @click="r.action" class="btn-sm">Consume</button>
73        </div>
74
75        <div class="btn-group">
76          <button @click="patchResources({ oxygen: 50, water: 800 })" class="btn">
77            $patch (O2=50, H2O=800)
78          </button>
79          <button @click="resetResources" class="btn btn-reset">
80            $reset
81          </button>
82        </div>
83      </div>
84
85      <div class="log-panel">
86        <h2>Activity Log</h2>
87        <div v-for="(log, i) in logs" :key="i" class="log-entry">
88          <span class="log-time">{{ log.time }}</span>
89          {{ log.message }}
90        </div>
91        <p v-if="!logs.length" class="empty">No activity yet...</p>
92      </div>
93    </div>
94  </div>
95</template>
96
97<style scoped>
98.nova-lab {
99  background: #0a0e27;
100  color: #00ff88;
101  min-height: 100vh;
102  padding: 20px;
103  font-family: monospace;
104}
105h1 { color: #00ff88; margin-bottom: 20px; text-align: center; }
106h2 { color: #00b4d8; margin-bottom: 15px; }
107.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; max-width: 700px; margin: 0 auto; }
108.resource-panel, .log-panel {
109  background: rgba(0, 180, 216, 0.1);
110  border: 2px solid #00b4d8;
111  padding: 15px;
112}
113.resource {
114  background: rgba(0, 255, 136, 0.05);
115  border: 1px solid #00ff88;
116  padding: 10px;
117  margin-bottom: 8px;
118}
119.r-header { display: flex; justify-content: space-between; margin-bottom: 5px; }
120.r-value { font-size: 1.2em; font-weight: bold; margin-bottom: 5px; }
121.ok { color: #00ff88; }
122.low { color: #ff4444; }
123.btn-sm {
124  background: #00b4d8;
125  color: #0a0e27;
126  border: none;
127  padding: 4px 12px;
128  cursor: pointer;
129  font-family: monospace;
130}
131.btn-group { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
132.btn {
133  background: #00b4d8;
134  color: #0a0e27;
135  border: none;
136  padding: 8px 12px;
137  cursor: pointer;
138  font-family: monospace;
139  font-size: 0.85em;
140}
141.btn:hover { background: #00ff88; }
142.btn-reset { background: #ff9900; }
143.log-entry {
144  padding: 5px 0;
145  border-bottom: 1px solid rgba(0, 180, 216, 0.3);
146  font-size: 0.85em;
147}
148.log-time { color: #00b4d8; margin-right: 8px; }
149.empty { color: #666; font-style: italic; }
150</style>

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. 1. Comment définit-on le state dans un store Pinia (Options API) ?

  2. 2. Que fait la méthode $patch dans Pinia ?

Voici 2 des 3 questions de cette leçon. Réponds aux autres dans le jeu.

Tâches pratiques dans le jeu

  • Éditeur de code

    Entraîne-toi à travailler avec le state et la méthode $patch

  • Tri vertical

    Ordonne les étapes de configuration de Pinia dans une application Vue

  • Clique dans l'ordre

    Ordonne les éléments pour utiliser correctement storeToRefs

  • Éditeur de code

    Entraîne-toi à utiliser $patch avec une fonction de rappel