Comprendre la différence entre composants fonctionnels et composants de classe dans React

August 18, 2020
Rédigé par
Shiori Yamazaki
Contributeur
Les opinions exprimées par les contributeurs de Twilio sont les leurs
Révisé par
Diane Phan
Twilion

difference composants react

Il existe dans le monde de React deux façons d'écrire des composants React. L'une utilise une fonction, et l'autre une classe. Les composants fonctionnels sont devenus ces derniers temps de plus en plus populaires, mais comment l'expliquer ?

Grâce à cet article expliquant pas à pas chacun d'eux à travers des exemples de code, vous comprendrez les différences entre composants fonctionnels et composants de classe et pourrez vous plonger dans le monde du React moderne !

Produire le rendu d'éléments JSX

Avant toute chose, la grande différence, c'est la syntaxe. Comme son nom l'indique, un composant fonctionnel n'est qu'une simple fonction JavaScript qui renvoie du JSX. Un composant de classe, pour sa part, est une classe JavaScript qui étend React.Component, laquelle comprend une méthode de rendu. Vous trouvez ça déroutant ? Prenons un exemple simple.

import React from "react";
 
const FunctionalComponent = () => {
 return <h1>Hello, world</h1>;
};

Comme vous le constatez, un composant fonctionnel est une fonction qui renvoie du JSX. Si vous ne connaissez pas les fonctions fléchées introduites dans ES6, vous pouvez également vous référer à l'exemple ci-dessous qui n'en présente pas.

import React from "react";

function FunctionalComponent() {
 return <h1>Hello, world</h1>;
}

Voir le rendu avec un composant fonctionnel dans CodePen

D'autre part, lorsque vous définissez un composant de classe, vous devez créer une classe qui étend React.Component. Le JSX à rendre sera renvoyé à l'intérieur de la méthode de rendu.

import React, { Component } from "react";

class ClassComponent extends Component {
 render() {
   return <h1>Hello, world</h1>;
 }
}

Vous retrouverez ci-dessous le même exemple, mais sans la déstructuration. Si vous ne connaissez pas déjà, vous pouvez en savoir plus sur la déstructuration et les fonctions fléchées introduites dans ES6 !

import React from "react";

class ClassComponent extends React.Component {
 render() {
   return <h1>Hello, world</h1>;
 }
}

Voir le rendu avec un composant de classe dans CodePen

Passer des propriétés

Passer des propriétés peut être déroutant, mais voyons comment les écrire à la fois dans les composants de classe et les composants fonctionnels. Imaginons que nous passons des propriétés ayant pour nom « Shiori », comme indiqué ci-dessous.

<Component name="Shiori" />
const FunctionalComponent = ({ name }) => {
 return <h1>Hello, {name}</h1>;
};

Dans un composant fonctionnel, les propriétés sont passées comme argument de la fonction. Notez que nous avons recours ici à la déstructuration. Sinon, il est également possible de l'écrire sans.

const FunctionalComponent = (props) => {
 return <h1>Hello, {props.name}</h1>;
};

Dans ce cas, il suffit d'utiliser props.name au lieu de name.

Voir les propriétés avec un composant fonctionnel dans CodePen

class ClassComponent extends React.Component {
  render() {
    const { name } = this.props;
    return <h1>Hello, { name }</h1>;
 }
}

Puisqu'il s'agit d'une classe, vous devez utiliser this pour faire référence aux propriétés. Et bien sûr, il est possible d'utiliser la déstructuration pour insérer name dans les propriétés tout en utilisant des composants à base de classes.

Voir les propriétés avec un composant de classe dans CodePen

Gérer l'état

Comme chacun sait, il n'y a aucun moyen d'éviter les variables d'état dans un projet React. Jusqu'à récemment, gérer l'état n'était possible que dans un composant de classe, mais depuis l'introduction du Hook React useState à partir de React 16.8, les développeurs peuvent maintenant écrire des composants fonctionnels avec état. Vous pouvez en savoir plus sur les Hooks en consultant la documentation officielle. Nous allons faire ici un simple compteur qui part de 0 et incrémente de 1 à chaque clic sur un bouton.

Gérer l'état dans les composants fonctionnels

const FunctionalComponent = () => {
 const [count, setCount] = React.useState(0);

 return (
   <div>
     <p>count: {count}</p>
     <button onClick={() => setCount(count + 1)}>Click</button>
   </div>
 );
};

Pour utiliser des variables d'état dans un composant fonctionnel, nous devons utiliser le Hook useState, qui prend un argument d'état initial. Dans le cas présent nous commençons par 0 clics, de sorte que l'état initial du compte soit 0.

Bien sûr, il peut y avoir plus de variété de l'état initial, y compris nullstring ou même object – tout type d'état autorisé par JavaScript ! Et sur le côté gauche, dans la mesure où useState renvoie l'état actuel et une fonction qui le met à jour, nous déstructurons le tableau comme ceci. Si les deux éléments du tableau vous semblent un peu déroutants, vous pouvez les voir comme un état et son setter (fonction qui permet d'effectuer une modification sur un objet ou propriété). Dans cet exemple, nous les avons nommés count et setCount pour faciliter la compréhension de la connexion entre les deux.

Voir l'état avec un composant fonctionnel dans CodePen

Gérer l'état dans les composants de classe

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

 render() {
   return (
     <div>
       <p>count: {this.state.count} times</p>
       <button onClick={() => this.setState({ count: this.state.count + 1 })}>
         Click
       </button>
     </div>
   );
 }
}

L'idée reste la même, mais un composant de classe traite l'état un peu différemment. Tout d'abord, nous devons comprendre l'importance du constructeur React.Component. Voici la définition qu'en offre la documentation officielle :

« Le constructeur d'un composant React est appelé avant que celui-ci ne soit monté. Quand on implémente le constructeur d'une sous-classe React.Component, il faut commencer par appeler super(props) avant toute autre instruction. Dans le cas contraire, this.props sera indéfini dans le constructeur, ce qui peut causer des bugs. »

En fait, si vous n'implémentez pas le constructeur et n'appelez pas super(props), toutes les variables d'état que vous essayez d'utiliser seront indéfinies. Définissons donc d'abord le constructeur. Dans le constructeur, vous créerez un objet d'état avec une clé d'état et une valeur initiale. Et dans JSX, nous utilisons this.state.count pour accéder à la valeur de la clé d'état que nous avons définie dans le constructeur afin d'afficher le compte. Le setter est plus ou moins le même, si ce n'est au niveau de la syntaxe qui est différente.

Sinon, vous pouvez également écrire une fonction onClick. N'oubliez pas que la fonction setState prend, si nécessaire, un ou plusieurs arguments d'état, et des propriétés (facultatif).

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

Voir l'état avec un composant de classe dans Codepen

Méthodes de cycle de vie

Pour finir, intéressons-nous aux cycles de vie. Allez, on y est presque ! Comme vous le savez déjà, les cycles de vie jouent un rôle important dans la synchronisation du rendu. Pour ceux d'entre vous qui migrent des composants de classe vers des composants fonctionnels, vous devez vous demander ce qui pourrait remplacer les méthodes de cycle de vie telles que componentDidMount() dans un composant de classe. Et oui, il existe pour ça un Hook qui fonctionne parfaitement. Découvrons-le ensemble !

Au montage (componentDidMount)

La méthode de cycle de vie componentDidMount est appelée juste après la fin du premier rendu. Il existait auparavant un componentWillMountqui se produisait avant le premier rendu, mais il est considéré comme du code hérité dont l'utilisation n'est pas recommandée dans les versions plus récentes de React.

const FunctionalComponent = () => {
 React.useEffect(() => {
   console.log("Hello");
 }, []);
 return <h1>Hello, World</h1>;
};

En remplaçant componentDidMount, nous utilisons le Hook useEffect avec le deuxième argument de []. Le deuxième argument du Hook useState est normalement un tableau d'un ou plusieurs états qui change, et useEffect sera uniquement appelé sur cette sélection de changements. Mais lorsqu'il s'agit d'un tableau vide comme le montre cet exemple, il sera appelé une fois lors du montage. C'est là le remplaçant idéal pour une méthode componentDidMount.

class ClassComponent extends React.Component {
 componentDidMount() {
   console.log("Hello");
 }

 render() {
   return <h1>Hello, World</h1>;
 }
}

Il se passe fondamentalement la même chose ici : componentDidMount est une méthode de cycle de vie qui est appelée une fois après le premier rendu.

Au démontage (componentWillUnmount)

const FunctionalComponent = () => {
 React.useEffect(() => {
   return () => {
     console.log("Bye");
   };
 }, []);
 return <h1>Bye, World</h1>;
};

J'ai le plaisir de vous dire que nous pouvons également utiliser un Hook useState pour le démontage. Mais attention, la syntaxe est un peu différente. Ce que vous devez faire, c'est renvoyer une fonction qui s'exécute au démontage à l'intérieur de la fonction useEffect. C'est particulièrement utile lorsque vous devez nettoyer les abonnements tels qu'une fonction clearInterval, mais cela peut aussi entraîner de graves fuites de mémoire sur les projets plus importants. L'un des avantages qu'il y a à utiliser useEffect, c'est que nous pouvons écrire des fonctions pour le montage et le démontage au même endroit.

class ClassComponent extends React.Component {
 componentWillUnmount() {
   console.log("Bye");
 }

 render() {
   return <h1>Bye, World</h1>;
 }
}

Voir le cycle de vie avec un composant fonctionnel dans Codepen

Voir le cycle de vie avec un composant de classe dans Codepen

Conclusion

Les deux styles présentent des avantages et des inconvénients, mais j'aimerais conclure en disant que les composants fonctionnels risquent bien de prendre la relève du React moderne dans un futur proche.

Comme nous l'avons remarqué dans les exemples, l'écriture d'un composant fonctionnel est plus courte et plus simple, facilitant ainsi le développement, la compréhension et le test. Les composants de classe peuvent également être déconcertants de par les nombreuses utilisations de this. Utiliser les composants fonctionnels permet d'éviter tout ce chantier et de maintenir le tout en ordre.

Il convient également de noter que l'équipe React prend en charge davantage de Hooks React pour les composants fonctionnels qui remplacent, voire améliorent, les composants de classe. En termes de suivi, l'équipe React a mentionné auparavant qu'elle allait optimiser les performances des composants fonctionnels en évitant les vérifications et les allocations de mémoire inutiles. Et aussi prometteur que cela puisse paraître, elle a introduit récemment de nouveaux Hooks pour des composants fonctionnels tels que useState ou useEffect, tout en assurant qu'elle n'allait pas rendre les composants de classe obsolètes.. L'équipe s'efforce d'adopter progressivement les composants fonctionnels avec des Hooks dans les cas les plus récents, ce qui signifie qu'il n'est pas nécessaire de basculer les projets existants utilisant des composants de classe en les réécrivant intégralement avec des composants fonctionnels pour qu'ils restent cohérents.

Une fois de plus, il existe dans React de nombreux styles de codage valables. Pour ma part, je préfère toutefois les composants fonctionnels aux composants de classe pour les raisons énumérées ci-dessus. J'espère que cet article vous aura aidé à vous familiariser avec le React moderne. Pour en savoir plus, consultez la documentation officielle ! Vous pouvez également consulter notre post sur la construction d'une appli vidéo Twilio afin de voir une utilisation pratique des composants fonctionnels avec des Hooks.

Shiori Yamazaki est stagiaire en ingénierie logicielle au sein de l'équipe Platform Experience. Elle adore développer des applications web modernes. Elle est joignable à l'adresse syamazaki [at] twilio.com ou sur LinkedIn.

Découvrez d'autres posts sur les mêmes sujets :

Ajoutez des filtres à votre application de visioconférence Twilio Video en utilisant FaceAPI, React Hooks et TypeScript

Découvrez comment ajouter des filtres sympas pour visages dans votre application vidéo React + TypeScript.

Construire un chat vidéo avec des Hooks React

Construisez une application de chat vidéo via Twilio Video et React uniquement à partir de composants fonctionnels, grâce aux Hooks useState, useCallback, useEffect et useRef.