212 lines
7.2 KiB
Plaintext
212 lines
7.2 KiB
Plaintext
---
|
|
sidebar_position: 5
|
|
title: "State et cycle de vie"
|
|
description: "Voyons ensemble comment gérer le state et le cycle de vie d'un composant React !"
|
|
tags:
|
|
- Frontend
|
|
- React
|
|
- JavaScript/TypeScript
|
|
- Bibliothèque
|
|
- Interface utilisateur (UI)
|
|
---
|
|
|
|
import Button from '@site/src/components/Button';
|
|
import Admonition from '@theme/Admonition';
|
|
import TabItem from '@theme/TabItem';
|
|
import Tabs from '@theme/Tabs';
|
|
|
|
# State et cycle de vie
|
|
|
|
## Introduction
|
|
|
|
Dans le précédent article, nous avons vu comment créer notre premier composant React avec notamment le concept de **props**.
|
|
|
|
Voyons maintenant comment gérer le **state** et le **cycle de vie** d'un composant React !
|
|
Commençons tranquillement avec le **cycle de vie** d'un composant, puisqu'il est indispensable pour comprendre le **state**.
|
|
|
|
<Admonition type="info" title="Rappel">
|
|
Dans cet article, on va utiliser des composants fonctionnels _(fonctions)_ plutôt que des composants de classe _(classes)_ pour déclarer nos composants React.
|
|
Pour rappel, les composants déclarés avec des classes ne sont plus recommandés par la [documentation officielle](https://react.dev/reference/react/Component).
|
|
</Admonition>
|
|
|
|
## 🔄 Cycle de vie
|
|
|
|
Le **cycle de vie** d'un composant React est une série d'étapes que traverse un composant, de sa création _(montage)_ à sa destruction _(démontage)_.
|
|
|
|
Voici les trois différentes étapes du cycle de vie d'un composant React :
|
|
|
|
1. **Montage** _(Mounting)_ : le composant est créé et inséré dans le DOM
|
|
2. **Mise à jour** _(Updating)_ : le composant est mis à jour suite à un changement de **props** ou de **state**
|
|
3. **Démontage** _(Unmounting)_ : le composant est retiré du DOM
|
|
|
|
On verra un peu plus en détail ces étapes dans l'article suivant qui traitera un certain hook de React : `useEffect`.
|
|
|
|
<Admonition type="quote" title="Hook.. comme le capitaine ? 🦜🏴☠️">
|
|
Haha, non !
|
|
|
|
Un hook en React, est une fonction qui permet d'exploiter les fonctionnalités de React dans un composant fonctionnel _(fonction)_.
|
|
|
|
Bon... c'est un peu du charabia, mais on verra ça plus en détail dans le prochain article car il y a beaucoup à dire sur les hooks !
|
|
</Admonition>
|
|
|
|
Mais pour le moment, restons en à une vue d'ensemble du cycle de vie !
|
|
|
|
## 🧠 State
|
|
|
|
Le **state** est un objet qui contient les données internes d'un composant.
|
|
Il est propre à chaque composant et peut être modifié par ce dernier _(à ne pas confondre avec les **props** qui elles sont immuables)_.
|
|
|
|
Mais alors, pourquoi utiliser un state alors qu'on pourrait tout simplement déclarer une variable dans notre composant ?
|
|
|
|
Prenons cet exemple :
|
|
|
|
<Tabs>
|
|
<TabItem value="js" label="JavaScript">
|
|
```jsx title="Counter.jsx" showLineNumbers
|
|
import React from 'react';
|
|
|
|
export const Counter = () => {
|
|
let count = 0;
|
|
|
|
const increment = () => {
|
|
count += 1;
|
|
console.log("Increment", count);
|
|
};
|
|
|
|
return (
|
|
<button onClick={increment}>{count}</button>
|
|
);
|
|
};
|
|
```
|
|
</TabItem>
|
|
|
|
<TabItem value="ts" label="TypeScript">
|
|
```tsx title="Counter.tsx" showLineNumbers
|
|
import React from 'react';
|
|
|
|
export const Counter = () => {
|
|
let count: number = 0;
|
|
|
|
const increment = () => {
|
|
count += 1;
|
|
console.log("Increment", count);
|
|
};
|
|
|
|
return (
|
|
<button onClick={increment}>{count}</button>
|
|
);
|
|
};
|
|
```
|
|
</TabItem>
|
|
</Tabs>
|
|
|
|
<Button href="https://playcode.io/1940681">
|
|
🕹️ Voir l'exemple sur PlayCode
|
|
</Button>
|
|
|
|
On serait tentés de croire que ce code fonctionne. Après tout, en vanilla JS _(JavaScript pur)_, on pourrait tout à fait faire ça !
|
|
Et maintenant tu t'en doutes _(sinon pourquoi j'en parlerai ?)_, ce code ne fonctionne pas.
|
|
|
|
Pourtant, si on regarde la console du navigateur on voit bien que la variable `count` est bien incrémentée !
|
|
|
|
La raison est très simple : React ne sait pas que la variable `count` a été modifiée.
|
|
Pour être plus précis, React ne sait pas qu'il doit mettre à jour l'interface utilisateur _(UI)_ suite à la modification de `count`.
|
|
|
|
C'est là qu'intervient le **state** !
|
|
Le state est **réactif** et permet à React de savoir quand il doit mettre à jour l'interface utilisateur _(UI)_.
|
|
|
|
### 📝 Déclaration du state
|
|
|
|
Pour déclarer un **state**, on utilise le hook `useState` de React.
|
|
|
|
<Tabs>
|
|
<TabItem value="js" label="JavaScript">
|
|
```jsx
|
|
const [count, setCount] = React.useState(0);
|
|
```
|
|
</TabItem>
|
|
|
|
<TabItem value="ts" label="TypeScript">
|
|
```tsx
|
|
const [count, setCount] = React.useState<number>(0);
|
|
```
|
|
</TabItem>
|
|
</Tabs>
|
|
|
|
Et là tu vas peut-être te demander une chose...
|
|
|
|
<Admonition type="quote" title="Ouh là... pourquoi on a deux assignements ?">
|
|
Bien vu ! Effectivement on va avoir deux assignements pour déclarer un **state** :
|
|
- `count` : la valeur du **state**
|
|
- `setCount` : la fonction qui permet de modifier la valeur du **state**
|
|
|
|
Si tu as déjà fait de la POO, le principe de **getter** et **setter** te sera familier puisque c'est un peu le même principe !
|
|
|
|
Le hook `useState` prend en paramètre la valeur initiale du **state** _(ici `0`)_ et retourne un tableau avec la valeur du **state** et la fonction pour le modifier.
|
|
</Admonition>
|
|
|
|
### 🔄 Utilisation du state
|
|
|
|
Maintenant que notre **state** est déclaré, on peut l'utiliser dans notre composant.
|
|
|
|
<Tabs>
|
|
<TabItem value="js" label="JavaScript">
|
|
```jsx title="Counter.jsx" showLineNumbers
|
|
import React from 'react';
|
|
|
|
export const Counter = () => {
|
|
const [count, setCount] = React.useState(0);
|
|
|
|
const increment = () => setCount(count + 1);
|
|
|
|
return (
|
|
<button onClick={increment}>{count}</button>
|
|
);
|
|
};
|
|
```
|
|
</TabItem>
|
|
|
|
<TabItem value="ts" label="TypeScript">
|
|
```tsx title="Counter.tsx" showLineNumbers
|
|
import React from 'react';
|
|
|
|
export const Counter = () => {
|
|
const [count, setCount] = React.useState<number>(0);
|
|
|
|
const increment = () => setCount(count + 1);
|
|
|
|
return (
|
|
<button onClick={increment}>{count}</button>
|
|
);
|
|
};
|
|
```
|
|
</TabItem>
|
|
</Tabs>
|
|
|
|
<Button href="https://playcode.io/1940705">
|
|
🕹️ Voir l'exemple sur PlayCode
|
|
</Button>
|
|
|
|
Et voilà ! Pas besoin de plus pour gérer un **state** en React 😉
|
|
|
|
Mais qu'est-ce qu'il se passe sous le capot ?
|
|
C'est un peu plus complexe que ça, mais pour faire simple :
|
|
|
|
#### ⚙️ Montage du composant _(Mounting)_
|
|
On vient prévenir React que notre composant va avoir un **state** et on lui donne une valeur initiale _(ici `0`)_.
|
|
|
|
#### 🔧 Mise à jour du composant _(Updating)_
|
|
Ce state, à chaque modification, va déclencher un nouveau rendu du composant.
|
|
|
|
#### 🗑️ Démontage du composant _(Unmounting)_
|
|
Et enfin, quand le composant est retiré du DOM, le state est détruit avec lui.
|
|
|
|
Ce fonctionnement est identique pour les props donnés à un composant d'ailleurs !
|
|
React est vraiment bien fait pour ça 😊
|
|
|
|
## Conclusion
|
|
|
|
Plutôt simple, non ?
|
|
Alors maintenant que tu sais comment gérer le **state** et le **cycle de vie** d'un composant React, tu es prêt à te pencher sur la prochaine étape _(et pas des moindres)_ : les **hooks** !
|
|
|
|
Mais pour l'heure, je te laisse jouer avec les **states** et les **props** pour bien comprendre comment tout ça fonctionne. |