Composants fonctionnels avec ou sans état dans React

React est une bibliothèque frontale JavaScript très utilisée pour la création d'interfaces utilisateur interactives. React a une courbe d'apprentissage relativement peu profonde, ce qui est l'une des raisons pour lesquelles il retient toute l'attention récemment. 

Bien qu'il y ait beaucoup de concepts importants à couvrir, les composants sont indéniablement le cœur et l'âme de React. Avoir une bonne compréhension des composants devrait vous faciliter la vie en tant que développeur React. 

Conditions préalables

Ce tutoriel est destiné aux débutants qui ont commencé à apprendre React et qui ont besoin d’une meilleure vue d’ensemble des composants. Nous commencerons par les notions de base des composants, puis nous passerons à des concepts plus complexes, tels que les modèles de composant et le moment d'utilisation de ces modèles. Différentes classifications de composants ont été couvertes, telles que les composants de classe par rapport aux composants fonctionnels, les composants avec état par rapport à par état, et les composants par conteneur par rapport aux éléments de présentation.. 

Avant de commencer, je voudrais vous présenter l'extrait de code que nous allons utiliser dans ce tutoriel. C'est un simple compteur construit avec React. Je reviendrai sur certaines parties de cet exemple tout au long du tutoriel.. 

Alors, commençons. 

Quels sont les composants?

Les composants sont des micro-entités autonomes et indépendantes qui décrivent une partie de votre interface utilisateur. L'interface utilisateur d'une application peut être divisée en composants plus petits, chaque composant ayant son propre code, sa propre structure et sa propre API.. 

Facebook, par exemple, possède des milliers de fonctionnalités interfacées lorsque vous affichez leur application Web. Voici un fait intéressant: Facebook comprend 30 000 composants et ce nombre augmente. L'architecture des composants vous permet de penser chaque pièce de manière isolée. Chaque composant peut tout mettre à jour dans son étendue sans se soucier de l'impact sur les autres composants. 

Si nous prenons l'exemple de l'interface utilisateur de Facebook, la barre de recherche serait un bon candidat pour un composant. Le fil d'actualité de Facebook créerait un autre composant (ou un composant hébergeant de nombreux sous-composants). Toutes les méthodes et tous les appels AJAX concernés par la barre de recherche seraient dans ce composant..

Les composants sont également réutilisables. Si vous avez besoin du même composant à plusieurs endroits, c'est facile. Avec l'aide de la syntaxe JSX, vous pouvez déclarer vos composants où vous voulez qu'ils apparaissent, et c'est tout. 

 
Nombre actuel: this.state.count
/ * Réutilisation des composants en action. * /

Props et State

Les composants ont besoin de données pour fonctionner. Vous pouvez combiner des composants et des données de deux manières différentes: soit en tant que les accessoires ou Etat. Les accessoires et l'état déterminent ce qu'un composant rend et comment il se comporte. Commençons par les accessoires.

les accessoires

Si les composants étaient des fonctions JavaScript simples, alors props serait l'entrée de la fonction. Selon cette analogie, un composant accepte une entrée (ce que nous appelons des accessoires), la traite, puis restitue du code JSX..

Bien que les données contenues dans les accessoires soient accessibles à un composant, la philosophie de React stipule que les accessoires doivent être immuables et descendants. Cela signifie qu'un composant parent peut transmettre toutes les données qu'il souhaite à ses enfants comme accessoires, mais le composant enfant ne peut pas modifier ses accessoires. Donc, si vous essayez de modifier les accessoires comme je l'ai fait ci-dessous, vous obtiendrez le "Impossible d'affecter en lecture seule" TypeError.

const Button = (props) => // les props sont en lecture seule props.count = 21;…

Etat

State, en revanche, est un objet appartenant au composant sur lequel il est déclaré. Sa portée est limitée au composant actuel. Un composant peut initialiser son état et le mettre à jour chaque fois que nécessaire. L'état du composant parent finit généralement par devenir les accessoires du composant enfant. Lorsque l'état est passé hors de la portée actuelle, nous l'appelons un accessoire.


Maintenant que nous connaissons les bases des composants, examinons la classification de base des composants..

Composants de classe et composants fonctionnels

Un composant React peut être de deux types: un composant de classe ou un composant fonctionnel. La différence entre les deux est évidente à partir de leurs noms. 

Composants fonctionnels

Les composants fonctionnels ne sont que des fonctions JavaScript. Ils prennent une entrée facultative qui, comme je l'ai mentionné plus tôt, est ce que nous appelons des accessoires.


Certains développeurs préfèrent utiliser les nouvelles fonctions de flèche ES6 pour définir les composants. Les fonctions fléchées sont plus compactes et offrent une syntaxe concise pour l'écriture d'expressions de fonctions. En utilisant une fonction de flèche, nous pouvons ignorer l'utilisation de deux mots-clés, une fonction et revenir, et une paire d'accolades. Avec la nouvelle syntaxe, vous pouvez définir un composant sur une seule ligne, comme ceci. 

const Hello = (name) => (
Bonjour, name!
)

Composants de classe

Les composants de classe offrent plus de fonctionnalités, et avec plus de fonctionnalités, plus de bagages. La principale raison de choisir des composants de classe sur des composants fonctionnels est qu’ils peuvent avoir Etat.

La syntaxe state = count: 1 fait partie de la fonctionnalité de champs de classe publics. Plus sur ce ci-dessous. 

Vous pouvez créer un composant de classe de deux manières. La manière traditionnelle est d'utiliser React.createClass (). ES6 a introduit un sucre de syntaxe qui vous permet d’écrire des classes qui s’étendent Composant de réaction. Cependant, les deux méthodes sont censées faire la même chose. 

Les composants de classe peuvent aussi exister sans état. Voici un exemple de composant de classe qui accepte un accessoire d’entrée et rend JSX.

la classe Hello étend React.Component constructor (props) super (props);  render () return ( 
Bonjour props
)

Nous définissons une méthode constructeur qui accepte les accessoires en entrée. À l'intérieur du constructeur, nous appelons super() transmettre tout ce qui est hérité de la classe parente. Voici quelques détails que vous avez peut-être manqués.

Tout d'abord, le constructeur est facultatif lors de la définition d'un composant. Dans le cas ci-dessus, le composant n'a pas d'état et le constructeur ne semble rien faire d'utile.. this.props utilisé à l'intérieur du rendre() fonctionnera que le constructeur soit défini ou non. Cependant, voici quelque chose de la documentation officielle:

Les composants de classe doivent toujours appeler le constructeur de base avec les accessoires.

Comme meilleure pratique, je recommanderai l’utilisation du constructeur pour tous les composants de classe..

Deuxièmement, si vous utilisez un constructeur, vous devez appeler super(). Ce n'est pas optionnel et vous obtiendrez l'erreur de syntaxe "Super () appel manquant constructeur" autrement. 

Et mon dernier point concerne l'utilisation de super() contre. super (accessoires). super (accessoires) devrait être utilisé si vous appelez this.props à l'intérieur du constructeur. Sinon, en utilisant super() seul suffit.

Composants avec état et composants sans état

C'est un autre moyen courant de classer les composants. Et les critères de classification sont simples: les composants qui ont un état et les composants qui ne le sont pas.. 

Composants avec état

Les composants avec état sont toujours des composants de classe. Comme mentionné précédemment, les composants avec état ont un état initialisé dans le constructeur. 

// Voici un extrait du contre-exemple constructor (props) super (props); this.state = count: 0; 

Nous avons créé un objet state et l'avons initialisé avec un nombre égal à 0. Une syntaxe alternative est proposée pour rendre cela plus facile, appelé champs de classe. Cela ne fait pas encore partie de la spécification ECMAScript, mais si vous utilisez un transpiler Babel, cette syntaxe devrait fonctionner immédiatement..

La classe App étend le composant / * // n'est plus nécessaire. constructor () super (); this.state = nombre: 1 * / state = nombre: 1; handleCount (valeur) this.setState ((prevState) => (count: prevState.count + valeur));  render () // omis par souci de brièveté

Vous pouvez éviter d'utiliser le constructeur complètement avec cette nouvelle syntaxe.

Nous pouvons maintenant accéder à l'état dans les méthodes de classe, y compris rendre(). Si vous allez les utiliser à l'intérieur rendre() pour afficher la valeur du nombre actuel, vous devez le placer entre accolades comme suit:

render () return (Nombre actuel: this.state.count)

le ce mot-clé fait ici référence à l'instance du composant actuel. 

Initialiser l'état n'est pas suffisant - nous devons pouvoir mettre à jour l'état afin de créer une application interactive. Si vous pensiez que cela fonctionnerait, non, ça ne va pas.

// Wrong way handleCount (valeur) this.state.count = this.state.count + valeur; 

 Les composants React sont équipés d'une méthode appelée setState pour mettre à jour l'état. setState accepte un objet contenant le nouvel état du compter.

// Ceci fonctionne handleCount (valeur) this.setState (nombre: this.state.count + valeur); 

le setState () accepte un objet comme entrée et on incrémente la valeur précédente de count par 1, ce qui fonctionne comme prévu. Cependant, il y a un hic. Lorsque plusieurs appels setState lisent une valeur précédente de l'état et y écrivent une nouvelle valeur, nous pouvons nous retrouver avec une condition de concurrence critique. Cela signifie que les résultats finaux ne correspondront pas aux valeurs attendues.

Voici un exemple qui devrait vous éclairer. Essayez ceci dans l'extrait de codesandbox ci-dessus.

// Quelle est l'attente de production? Essayez-le dans le bac à sable du code. handleCount (valeur) this.setState (count: this.state.count + 100); this.setState (count: this.state.count + value); this.setState (count: this.state.count-100); 

Nous voulons que setState incrémente le nombre de 100, puis le mette à jour de 1, puis supprime les 100 déjà ajoutés. Si setState effectue la transition d'état dans l'ordre actuel, nous obtiendrons le comportement attendu. Toutefois, setState est asynchrone et plusieurs appels setState peuvent être mis en lots pour une meilleure expérience et des performances de l'interface utilisateur. Donc, le code ci-dessus donne un comportement différent de celui attendu.

Par conséquent, au lieu de passer directement un objet, vous pouvez transmettre une fonction de mise à jour ayant la signature:

(prevState, props) => stateChange 

prevState est une référence à l'état précédent et est garanti pour être à jour. props fait référence aux accessoires du composant, et nous n'avons pas besoin d'accessoires pour mettre à jour l'état ici, nous pouvons donc l'ignorer. Par conséquent, nous pouvons l’utiliser pour mettre à jour l’état et éviter la condition de concurrence critique.

// La bonne façon handleCount (valeur) this.setState ((prevState) => count: prevState.count +1); 

le setState () rerender le composant, et vous avez un composant stateful qui fonctionne.

Composants sans état

Vous pouvez utiliser une fonction ou une classe pour créer des composants sans état. Toutefois, sauf si vous devez utiliser un hook de cycle de vie dans vos composants, vous devez opter pour des composants fonctionnels sans état. Si vous décidez d'utiliser des composants fonctionnels sans état ici, vous bénéficiez de nombreux avantages. ils sont faciles à écrire, à comprendre et à tester, et vous pouvez éviter la ce mot clé tout à fait. Cependant, à partir de React v16, l'utilisation de composants fonctionnels sans état par rapport aux composants de classe ne présente aucun avantage en termes de performances.. 

L'inconvénient est que vous ne pouvez pas avoir d'hameçons de cycle de vie. La méthode du cycle de vie ShouldComponentUpdate () est souvent utilisé pour optimiser les performances et pour contrôler manuellement ce qui est rendu. Vous ne pouvez pas encore l'utiliser avec des composants fonctionnels. Les références ne sont pas non plus supportées.

Composants de conteneur et composants de présentation

Ceci est un autre motif très utile lors de l'écriture de composants. L'avantage de cette approche est que la logique de comportement est séparée de la logique de présentation.

Composants de présentation

Les composants de présentation sont associés à la vue ou à l’apparence. Ces composants acceptent les accessoires de leur contrepartie conteneur et les rendent. Tout ce qui a trait à la description de l'interface utilisateur devrait aller ici. 

Les composants de présentation sont réutilisables et doivent rester découplés de la couche comportementale. Un composant de présentation reçoit les données et les rappels exclusivement via des accessoires et lorsqu'un événement survient, comme un bouton enfoncé, il appelle le composant conteneur via les accessoires pour appeler une méthode de gestion des événements.. 

Les composants fonctionnels doivent être votre premier choix pour l'écriture de composants de présentation, sauf si un état est requis. Si un composant de présentation nécessite un état, il doit concerner l'état de l'interface utilisateur et non les données réelles. Le composant de présentation n'interagit pas avec le magasin Redux ni ne fait d'appels d'API. 

Composants du conteneur

Les composants de conteneur traiteront de la partie comportementale. Un composant conteneur indique au composant de présentation ce qui doit être rendu à l'aide d'accessoires. Il ne devrait pas contenir de balises et de styles DOM limités. Si vous utilisez Redux, un composant conteneur contient le code qui envoie une action à un magasin. Sinon, c'est l'endroit où vous devez placer vos appels d'API et stocker le résultat dans l'état du composant.. 

La structure habituelle est qu’il existe un composant conteneur en haut qui transmet les données à ses composants de présentation enfants en tant qu’accessoires. Cela fonctionne pour des projets plus petits. Cependant, lorsque le projet prend de l'ampleur et que vous avez beaucoup de composants intermédiaires qui acceptent uniquement les accessoires et les transmettent aux composants enfants, cela devient difficile et difficile à maintenir. Lorsque cela se produit, il est préférable de créer un composant conteneur unique au composant feuille, ce qui allégera le fardeau des composants intermédiaires..

Alors, quel est un PureComponent?

Vous entendrez souvent le terme «composant pur» dans les cercles React, puis il y a React.PureComponent. Lorsque vous êtes nouveau sur React, tout cela peut sembler un peu déroutant. Un composant est dit pur s'il est garanti de retourner le même résultat avec les mêmes accessoires et le même état. Un composant fonctionnel est un bon exemple de composant pur car, avec une entrée, vous savez ce qui sera rendu.. 

const HelloWorld = (name) => ( 
'Salut $ name'
)

Les composants de classe peuvent être purs aussi longtemps que leurs accessoires et leur état sont immuables. Si vous avez un composant avec un ensemble d'accessoires et d'états immuables «profonds», l'API de React a quelque chose qui s'appelle PureComponent. React.PureComponent est similaire à Composant de réaction, mais il met en œuvre le ShouldComponentUpdate () méthode un peu différemment. ShouldComponentUpdate () est invoqué avant que quelque chose soit restitué. Le comportement par défaut est qu'il renvoie true, de sorte que toute modification de l'état ou des accessoires restitue le composant..

shouldComponentUpdate (nextProps, nextState) return true; 

Cependant, avec PureComponent, il effectue une comparaison peu profonde des objets. Une comparaison superficielle signifie que vous comparez le contenu immédiat des objets au lieu de comparer de manière récursive toutes les paires clé / valeur de l'objet. Ainsi, seules les références d'objet sont comparées, et si l'état / les accessoires sont mutés, cela pourrait ne pas fonctionner comme prévu. 

React.PureComponent est utilisé pour optimiser les performances, et il n'y a aucune raison pour laquelle vous devriez envisager de l'utiliser, sauf si vous rencontrez un problème de performances. 

Dernières pensées

Les composants fonctionnels sans état sont plus élégants et constituent généralement un bon choix pour la construction des composants de présentation. Parce qu'elles ne sont que des fonctions, vous n'aurez pas de difficulté à les écrire et à les comprendre, et en plus, elles sont extrêmement faciles à tester.. 

Il convient de noter que les composants fonctionnels sans état n’ont pas le dessus en termes d’optimisation et de performances car ils n’ont pas de ShouldComponentUpdate () crochet. Cela pourrait changer dans les futures versions de React, où les composants fonctionnels pourraient être optimisés pour de meilleures performances. Toutefois, si vous n'êtes pas critique à la performance, vous devez vous en tenir aux composants fonctionnels pour la vue / présentation et aux composants de classe avec état pour le conteneur..

J'espère que ce tutoriel vous a fourni une vue d'ensemble de l'architecture basée sur les composants et des modèles de composants différents dans React. Que pensez-vous de ceci? Partagez-les à travers les commentaires.

React a acquis une popularité croissante au cours des deux dernières années. En fait, nous avons un certain nombre d’articles sur Envato Market qui sont disponibles à l’achat, à la révision, à la mise en oeuvre, etc. Si vous recherchez des ressources supplémentaires autour de React, n'hésitez pas à les consulter..