État du composant React (State)

Les composants peuvent avoir un état, qui est la partie privée des données du composant et peut être utilisé pour gérer des données dynamiques.

L'état s'applique uniquement aux composants de classe, ou il peut être utilisé dans les composants fonction lors de l'utilisation des Hooks React.

React traite les composants comme des machines à états. Grâce à l'interaction avec les utilisateurs, différents états sont mis en œuvre, puis l'interface utilisateur est rendue pour maintenir la cohérence de l'interface utilisateur avec les données.

Dans React, il vous suffit de mettre à jour l'état du composant, puis de re-rendre l'interface utilisateur en fonction du nouvel état (ne manipulez pas le DOM).

L'exemple suivant crée une classe ES6 dont le nom étend React.Component, et utilise this.state dans la méthode render() pour modifier l'heure actuelle.

Ajoutez un constructeur de classe pour initialiser l'état this.state. Les composants de classe doivent toujours appeler le constructeur de base avec props.


Gestion de l'état dans les composants de classe

Créez un composant de classe avec état :

fichier Counter.js

import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  increment = () => {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}

export default Counter;

Affichez le composant dans src/index.js :

Exemple

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Counter from './Counter';

const root = ReactDOM.createRoot(document.getElementById("root"));
// Afficher le composant Counter
root.render(<Counter />);

Gestion d'état dans les composants fonctionnels (en utilisant les Hooks)

En utilisant les Hooks React, vous pouvez utiliser l'état dans les composants fonctionnels. Le Hook le plus couramment utilisé est useState.

Créez un composant fonctionnel avec état :

fichier Counter.js

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Compteur: {count}</p>
      <button onClick={() => setCount(count + 1)}>Bouton</Incrémenter>
    </div>
  );
}

export default Counter;

Affichez le composant dans src/index.js :

Exemple

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Counter from './Counter';

const root = ReactDOM.createRoot(document.getElementById("root"));
// Afficher le composant Counter
root.render(<Counter />);

Exemple

Créez un exemple Clock pour comprendre l'état du composant :

Exemple React

class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return ( <div> <h1>Bonjour, monde!</h1> <h2>Il est{this.state.date.toLocaleTimeString()}.</h2> </div> ); } } const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <Clock /> );

Essayez-le »

Ensuite, nous allons faire en sorte que le composant Clock configure son propre minuteur et se mette à jour chaque seconde.

Ajout de méthodes de cycle de vie à la classe

Dans les applications comportant de nombreux composants, il est très important de libérer les ressources utilisées par les composants lorsqu'ils sont détruits.

Lorsque le composant Clock est chargé pour la première fois dans le DOM, nous voulons configurer un minuteur. C'est ce qu'on appelle dans Reactle montage。

De même, lorsque le DOM généré par Clock est supprimé, nous voulons également annuler le minuteur. C'est ce qu'on appelle dans Reactle démontage。

Nous pouvons déclarer des méthodes spéciales sur la classe du composant pour exécuter du code lorsque le composant est monté ou démonté :

Exemple React

class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Bonjour, monde!</h1> <h2>Il est{this.state.date.toLocaleTimeString()}.</h2> </div> ); } } const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <Clock /> );

Essayez-le »

Analyse de l'exemple :

componentDidMount()etcomponentWillUnmount()Ces méthodes sont appelées des hooks de cycle de vie.

Une fois que la sortie du composant est rendue dans le DOM, le hookcomponentDidMount()est exécuté, et nous pouvons configurer un minuteur dans ce hook.

this.timerID est l'ID du minuteur, et nous pouvonscomponentWillUnmount()annuler le minuteur dans le hook.

Ordre d'exécution du code :

  1. Quand<Clock />est passé àReactDOM.render(), React appelleClockle constructeur du composant. CommeClockdoit afficher l'heure actuelle, il s'initialise avec un objet contenant l'heure actuellethis.state. Nous mettrons à jour cet état plus tard.

  2. React appelle ensuiteClockdu composantrender()méthode. C'est ainsi que React sait ce qui doit être affiché à l'écran, puis React met à jour le DOM pour qu'il correspondeClockla sortie de rendu de

  3. QuandClockLorsque la sortie de est insérée dans le DOM, React appellecomponentDidMount()le hook de cycle de vie. Dans celui-ci,Clockle composant demande au navigateur de mettre en place un minuteur pour appeler une fois par secondetick()。

  4. Le navigateur appelle latick()méthode chaque seconde. À l'intérieur,Clockle composant appellesetState()avec un objet contenant l'heure actuelle pour planifier une mise à jour de l'interface utilisateur. En appelantsetState(), React sait que l'état a changé et appellerender()à nouveau pour déterminer ce qui doit être affiché à l'écran. Cette fois,render()dans la méthode,this.state.datesera différent, donc la sortie de rendu contiendra l'heure mise à jour, et le DOM est mis à jour en conséquence.

  5. Une fois que leClockcomposant est retiré du DOM, React appellecomponentWillUnmount()cette fonction de hook, et le minuteur sera effacé.

Les données circulent du haut vers le bas

Ni les composants parents ni les composants enfants ne peuvent savoir si un composant est avec état ou sans état, et ils ne devraient pas se préoccuper de savoir si un composant est défini comme une fonction ou une classe.

C'est pourquoi l'état est souvent appelé local ou encapsulé. Aucun autre composant ne peut y accéder, à part le composant qui le possède et le définit.

Dans l'exemple suivant, le composant FormattedDate reçoit la valeur de date dans ses props, et ne sait pas si elle provient de l'état de Clock, des props de Clock ou d'une saisie manuelle :

Exemple React

function FormattedDate(props) { return <h2>Il est{props.date.toLocaleTimeString()}.</h2>; } class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Bonjour, world!</h1> <FormattedDate date={this.state.date} /> </div> ); } } const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <Horloge /> );

Essayez-le »

C'est souvent appelé flux de données descendant ou unidirectionnel. Tout état est toujours détenu par un composant spécifique, et toute donnée ou UI dérivée de cet état ne peut affecter que les composants situés en dessous dans l'arbre.

Si vous imaginez un arbre de composants comme une cascade de props, l'état de chaque composant est comme une source d'eau supplémentaire qui rejoint à un point arbitraire mais s'écoule aussi vers le bas.

Pour montrer que tous les composants sont vraiment isolés, nous pouvons créer un composant App qui rend trois composants Clock :

Exemple React

function FormattedDate(props) { return <h2>Il est{props.date.toLocaleTimeString()}.</h2>; } class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Bonjour, world!</h1> <FormattedDate date={this.state.date} /> </div> ); } } function App() { return ( <div> <Clock /> <Clock /> <Clock /> </div> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<App />);

Essayez-le »

Dans l'exemple ci-dessus, chaque composant Clock configure son propre minuteur et se met à jour indépendamment.

Dans les applications React, le fait qu'un composant soit avec état ou sans état est considéré comme un détail d'implémentation du composant qui peut changer au fil du temps.

Nous pouvons utiliser des composants sans état à l'intérieur de composants avec état, et nous pouvons également utiliser des composants avec état à l'intérieur de composants sans état.

Autres extensions