
Salut, habrozhiteli! L'édition originale est sortie à l'automne 2017, mais est toujours considérée comme le meilleur livre pour explorer React. L'auteur met constamment à jour et modifie le code du livre dans le référentiel
Github .
Nous vous proposons dans un billet de vous familiariser avec le passage "Les États et leur rôle dans la nature interactive de React"
Si vous ne deviez lire qu'un seul chapitre de ce livre, vous devriez choisir celui-ci! Sans états, les composants React ne sont rien de plus que des modèles statiques avancés. J'espère que vous partagerez mon enthousiasme car la compréhension des concepts de ce chapitre vous permettra de créer des applications beaucoup plus intéressantes.
Imaginez que vous créez un champ de saisie avec saisie semi-automatique (Fig. 4.1). Lors de la saisie de données, le champ doit envoyer une demande au serveur pour obtenir des informations sur les options appropriées pour afficher la sortie sur une page Web. Vous avez travaillé avec des propriétés jusqu'à présent et vous savez que la modification des propriétés vous permet d'obtenir différentes vues. Cependant, les propriétés ne peuvent pas être modifiées dans le contexte du composant actuel, car elles sont transmises lors de la création du composant.

En d'autres termes, les propriétés sont immuables dans le composant actuel, ce qui signifie que vous ne pouvez pas modifier les propriétés de ce composant à moins de recréer le composant et de transmettre les nouvelles valeurs à partir du parent (Fig. 4.2). Mais les informations reçues du serveur doivent être stockées quelque part, puis une nouvelle liste d'options doit être affichée dans la vue. Comment mettre à jour la vue si les propriétés ne peuvent pas être modifiées?
Une solution possible consiste à rendre un élément avec de nouvelles propriétés chaque fois que vous recevez une nouvelle réponse du serveur. Mais alors vous devez placer la logique en dehors du composant - et le composant cesse d'être autosuffisant. De toute évidence, si les valeurs des propriétés ne peuvent pas être modifiées et que la saisie semi-automatique doit être autosuffisante, il est impossible d'utiliser des propriétés. Ensuite, la question se pose: comment mettre à jour les vues en réponse aux événements sans recréer le composant (createElement () ou JSX <NAME />)? C'est ce problème que les États résolvent.
Une fois la réponse du serveur prête, le code de rappel change l'état du composant en conséquence. Vous devrez écrire ce code vous-même. Cependant, une fois l'état mis à jour, React mettra automatiquement à jour la vue pour vous (uniquement aux endroits où elle doit être mise à jour, c'est-à-dire là où les données d'état sont utilisées).
Grâce à l'état des composants React, vous pouvez créer des applications React interactives et significatives. L'état est un concept fondamental qui vous permet de créer des composants React qui peuvent stocker des données et mettre à jour automatiquement les vues en fonction des changements dans les données.
Quel est l'état du composant React?
L'état React est un stockage de données de composants modifiables - blocs autonomes orientés fonction de l'interface utilisateur et de la logique. «Variabilité» signifie que les valeurs d'état peuvent changer. En utilisant l'état dans la vue (render ()) et en modifiant les valeurs ultérieurement, vous pouvez influencer l'apparence de la vue.
Métaphore: si vous imaginez un composant sous la forme d'une fonction, à l'entrée de laquelle les propriétés et l'état sont transmis, le résultat de la fonction sera une description de l'interface utilisateur (présentation). Les propriétés et les états développent les vues, mais ils sont utilisés à des fins différentes (voir la section 4.3).
Lorsque vous travaillez avec des États, vous y accédez par nom. Le nom est un attribut (c'est-à-dire une clé d'objet ou une propriété d'objet - pas une propriété de composant) de cet objet .state, par exemple this.state.autocompleMatches ou this.state.inputFieldValue.
Les données d'état sont souvent utilisées pour afficher des informations dynamiques dans une vue afin d'étendre le rendu des vues. Revenons à un exemple précédent d'un champ de saisie semi-automatique: l'état change en réponse à une demande XHR au serveur, qui, à son tour, est initiée en entrant des données dans le champ. React garantit que les vues sont mises à jour lorsque l'état utilisé dans les vues change. En fait, lorsqu'un état change, seules les parties correspondantes des représentations changent (en éléments individuels et même en valeurs d'attribut d'un élément individuel).
Tout le reste dans le DOM reste inchangé. Ceci est possible grâce au modèle DOM virtuel (voir section 1.1.1), que React utilise pour déterminer le delta (ensemble de modifications) pendant le processus de réconciliation. Ce fait vous permet d'écrire du code dans un style déclaratif. React fait toute la routine pour vous. Les principales étapes du changement de présentation sont discutées au chapitre 5.
Les développeurs de React utilisent des états pour générer de nouvelles interfaces utilisateur. Les propriétés de composant (this.props), les variables ordinaires (inputValue) et les attributs de classe (this.inputValue) ne conviennent pas à cela, car la modification de leurs valeurs (dans le contexte du composant actuel) ne déclenche pas de changement dans la vue. Par exemple, l'extrait de code suivant est antipattern, ce qui montre que la modification de la valeur n'importe où sauf l'état n'entraînera pas l'actualisation de la vue:
// : ! let inputValue = 'Texas' class Autocomplete extends React.Component { updateValues() ← { ( ) this.props.inputValue = 'California' inputValue = 'California' this.inputValue = 'California' } render() { return ( <div> {this.props.inputValue} {inputValue} {this.inputValue} </div> ) } }
Voyons maintenant comment travailler avec les états des composants React.
Travailler avec les États
Pour travailler avec des états, vous devez pouvoir accéder aux valeurs, les mettre à jour et définir les valeurs initiales. Commençons par faire référence aux états dans les composants React.
Accès aux états
L'objet d'état est un attribut du composant, et vous devez y accéder via le lien this, par exemple this.state.name. Comme vous vous en souvenez, les variables sont accessibles et affichées en code JSX entre accolades ({}). De même, dans render (), vous pouvez rendre this.state (comme toute autre variable ou attribut de classe d'un composant non standard), par exemple {this.state.inputFieldValue}. Cette syntaxe est similaire à la syntaxe d'accès aux propriétés de this.props.name.

Nous utilisons ce que vous avez appris pour implémenter l'horloge de la fig. 4.3. Notre objectif est de créer une classe de composants autonome que n'importe qui peut importer et utiliser dans son application sans trop de tracas. L'horloge doit afficher l'heure actuelle.
Le projet a la structure suivante:
/clock index.html /jsx script.jsx clock.jsx /js script.js clock.js react.js react-dom.js
J'utilise la CLI Babel avec des indicateurs de suivi (-w) et un répertoire (-d) pour compiler tous les fichiers source JSX de clock / jsx vers le dossier clock / js cible et recompiler lorsque des changements sont détectés. De plus, j'ai enregistré la commande en tant que script npm dans le fichier package.json du dossier parent ch04 pour exécuter la commande npm run build-clock depuis ch04:
"scripts": { "build-clock": "./node_modules/.bin/babel clock/jsx -d clock/js -w" },
Bien sûr, le temps ne s'arrête pas (que cela nous plaise ou non). Pour cette raison, vous devez constamment mettre à jour la vue, et pour cela, vous pouvez utiliser l'état. Nommez-le currentTime et essayez de rendre l'état comme indiqué dans l'extrait 4.1.
Listing 4.1. Rendu d'état JSX
class Clock extends React.Component { render() { return <div>{this.state.currentTime}</div> } } ReactDOM.render( <Clock />, document.getElementById('content') )
Vous recevrez un message d'erreur: TypeError non capturé: Impossible de lire la propriété 'currentTime' de null. Habituellement, les messages d'erreur JavaScript ont les mêmes avantages qu'un verre d'eau froide pour une personne qui se noie. Il est bon qu'au moins dans ce cas, JavaScript affiche un message significatif.
Le message indique que la valeur de currentTime n'est pas définie. Contrairement aux propriétés, les états ne sont pas définis dans le parent. L'appel de setState dans render () échoue également, car cela créera une boucle (setState -> render -> setState ...) - et React signalera une erreur.
État initial
Vous avez déjà vu qu'avant d'utiliser les données d'état dans render (), vous devez initialiser l'état. Pour définir l'état initial, utilisez this.state dans le constructeur avec la syntaxe de la classe ES6 React.Component. N'oubliez pas d'appeler super () avec des propriétés; sinon, la logique du parent (React.Component) ne fonctionnera pas:
class MyFancyComponent extends React.Component { constructor(props) { super(props) this.state = {...} } render() { ... } }
Lors de l'attribution de l'état initial, vous pouvez également ajouter une autre logique - par exemple, définir la valeur de currentTime à l'aide de new Date (). Vous pouvez même utiliser toLocaleString () pour obtenir le format de date / heure correct pour l'emplacement actuel de l'utilisateur, comme indiqué ci-dessous (ch04 / horloge).
Listing 4.2. Constructeur de composants d'horloge
class Clock extends React.Component { constructor(props) { super(props) this.state = {currentTime: (new Date()).toLocaleString()} } ... }
La valeur de this.state doit être un objet. Nous n'entrerons pas dans les détails du constructeur () d'ES6; reportez-vous à l'annexe D et au résumé
ES6 sur
github.com/azat-co/cheatsheets/tree/master/es6 . L'essentiel est que, comme dans d'autres langages OOP, un constructeur (c'est-à-dire constructor ()) est appelé lorsqu'une instance de la classe est créée. Le nom de la méthode constructeur doit être exactement cela; considérez celle-ci comme l'une des règles de l'ES6. De plus, lors de la création de la méthode constructor (), l'appel super () doit presque toujours y être inclus, sans lequel le constructeur du parent ne serait pas exécuté. En revanche, si vous ne définissez pas la méthode constructor (), l'appel à super () sera supposé par défaut.
Le nom currentTime est facultatif; vous devez utiliser le même nom ultérieurement lors de la lecture et de la mise à jour de cet état.
L'objet d'état peut contenir des objets ou des tableaux imbriqués. L'exemple suivant ajoute un tableau de descriptions de livres à l'état:
class Content extends React.Component { constructor(props) { super(props) this.state = { githubName: 'azat-co', books: [ 'pro express.js', 'practical node.js', 'rapid prototyping with js' ] } } render() { ... } }
La méthode constructor () n'est appelée qu'une seule fois, lors de la création d'un élément React basé sur la classe. Ainsi, vous ne pouvez définir l'état directement en utilisant this.state qu'une seule fois - dans la méthode constructor (). Ne définissez pas ou ne mettez pas à jour l'état directement avec this.state = ... ailleurs, car cela peut entraîner des conséquences imprévues.
Ainsi, vous n'obtenez que la valeur initiale, qui deviendra très rapidement obsolète - en seulement 1 seconde. Qui a besoin d'une montre qui ne montre pas l'heure actuelle? Heureusement, il existe un mécanisme de mise à jour de l'état actuel.
Mise à jour du statut
L'état est modifié par la méthode de la classe this.setState (data, callback). Lorsque cette méthode est appelée, React combine les données avec les états actuels et appelle render (), après quoi elle appelle le rappel.
La définition d'un rappel de rappel dans setState () est importante car la méthode fonctionne de manière asynchrone. Si l'application dépend du nouvel état, vous pouvez utiliser ce rappel pour vous assurer que le nouvel état est devenu disponible.
Si vous supposez simplement que l'état a été mis à jour sans attendre la fin de setState (), c'est-à-dire qu'il fonctionne de manière synchrone lors de l'exécution d'une opération asynchrone, une erreur peut se produire: le programme dépend de la mise à jour des valeurs d'état, mais l'état reste ancien.
Jusqu'à présent, nous avons rendu le temps à l'État. Vous savez déjà comment définir l'état initial, mais il devrait être mis à jour toutes les secondes, non? Pour ce faire, utilisez la fonction de minuterie du navigateur setInterval () (http://mng.bz/P2d6), qui mettra à jour l'état toutes les n millisecondes. La méthode setInterval () est implémentée dans presque tous les navigateurs modernes comme globale, ce qui signifie qu'elle peut être utilisée sans bibliothèques ou préfixes supplémentaires. Un exemple:
setInterval(()=>{ console.log('Updating time...') this.setState({ currentTime: (new Date()).toLocaleString() }) }, 1000)
Pour démarrer le compte à rebours, vous devez appeler setInterval () une seule fois. Nous créons la méthode launchClock () uniquement à cette fin; launchClock () sera appelé dans le constructeur. La version finale du composant est présentée dans le Listing 4.3 (ch04 / clock / jsx / clock.jsx).
La méthode setState () peut être appelée n'importe où, pas seulement dans la méthode launchClock () (qui est appelée dans le constructeur), comme dans l'exemple. En règle générale, la méthode setState () est appelée à partir d'un gestionnaire d'événements ou en tant que rappel lorsque des données sont reçues ou mises à jour.
CONSEIL Une tentative de changer l'état dans le code avec une commande de la forme this.state.name = 'nouveau nom' ne mènera à rien. Cela ne conduira pas à un nouveau rendu et à une mise à jour du vrai modèle DOM, ce que vous souhaitez. Dans la plupart des cas, un changement d'état direct sans setState () est anti-modèle et doit être évité.
Il est important de noter que la méthode setState () ne met à jour que les états qui lui ont été transmis (partiellement ou fusionnés, mais sans remplacement complet). Il ne remplace pas à chaque fois l'intégralité de l'objet d'état. Par conséquent, si un seul des trois états a changé, les deux autres resteront inchangés. Dans l'exemple suivant, userEmail et userId ne changeront pas:
constructor(props) { super(props) this.state = { userName: 'Azat Mardan', userEmail: 'hi@azat.co', userId: 3967 } } updateValues() { this.setState({userName: 'Azat'}) }
Si vous avez l'intention de mettre à jour les trois états, vous devrez le faire explicitement en transmettant les nouvelles valeurs de ces états à setState (). (Également dans l'ancien code, qui ne fonctionne plus, la méthode this.replaceState () est parfois trouvée; elle est officiellement obsolète.1. Comme vous pouvez le deviner par son nom, elle a remplacé l'objet d'état entier par tous ses attributs.)
N'oubliez pas que l'appel à setState () lance l'exécution de render (). Dans la plupart des cas, cela fonctionne. Dans certains cas particuliers où le code dépend de données externes, vous pouvez lancer un nouveau rendu en appelant this.forceUpdate (). Néanmoins, de telles décisions ne sont pas souhaitables, car le fait de s'appuyer sur des données externes (au lieu de l'état) rend les composants moins fiables et dépendants de facteurs externes (liaison stricte).
Comme mentionné précédemment, l'objet état est accessible dans l'entrée this.state. Dans JSX, les valeurs de sortie sont placées entre accolades ({}), par conséquent, pour déclarer une propriété d'état dans une vue (c'est-à-dire dans la commande de retour de la méthode de rendu), utilisez la notation {this.state.NAME}.
React magic se produit lorsque vous utilisez des données d'état dans une vue (par exemple, en sortie, dans une commande if / else, en tant que valeur d'attribut ou valeur de propriété d'un enfant), puis passez de nouvelles valeurs setState (). Bah! React met à jour tout le balisage HTML nécessaire pour vous. Vous pouvez le vérifier dans la console DevTools, où les cycles "Updating ..." et "Rendering ..." doivent être affichés. Et la grande chose est que cela n'affectera que les éléments DOM minimum requis absolus.
»Plus d'informations sur le livre sont disponibles sur
le site Web de l'éditeur»
Contenu»
Extrait20% de réduction sur les colporteurs -
ReactLors du paiement de la version papier du livre, une version électronique du livre est envoyée par e-mail.