Tutoriel React Partie 25: Atelier sur les formulaires

Dans la partie d'aujourd'hui de la traduction du cours de formation React, vous êtes invité à remplir une tâche de formulaire.

image

Partie 1: aperçu du cours, raisons de la popularité de React, ReactDOM et JSX
Partie 2: composants fonctionnels
Partie 3: fichiers composants, structure du projet
Partie 4: composants parent et enfant
Partie 5: début des travaux sur une application TODO, les bases du style
Partie 6: sur certaines fonctionnalités du cours, JSX et JavaScript
Partie 7: styles en ligne
Partie 8: poursuite des travaux sur l'application TODO, familiarité avec les propriétés des composants
Partie 9: propriétés des composants
Partie 10: Atelier sur l'utilisation des propriétés et du style des composants
Partie 11: génération de balisage dynamique et méthode des tableaux de cartes
Partie 12: atelier, troisième étape de travail sur une application TODO
Partie 13: composants basés sur les classes
Partie 14: atelier sur les composants basés sur les classes, état des composants
Partie 15: ateliers santé composante
Partie 16: quatrième étape de travail sur une application TODO, gestion d'événements
Partie 17: cinquième étape de travail sur une application TODO, modifiant l'état des composants
Partie 18: la sixième étape de travail sur une application TODO
Partie 19: méthodes du cycle de vie des composants
Partie 20: la première leçon de rendu conditionnel
Partie 21: deuxième leçon et atelier sur le rendu conditionnel
Partie 22: la septième étape des travaux sur une application TODO, téléchargement de données depuis des sources externes
Partie 23: première leçon sur l'utilisation des formulaires
Partie 24: Deuxième leçon sur les formulaires
Partie 25: Atelier sur l'utilisation des formulaires
Partie 26: architecture d'application, modèle de conteneur / composant
Partie 27: projet de cours

Leçon 43. Atelier. Travailler avec des formulaires


Original

▍Emploi


Dans cette leçon pratique, vous êtes invité à afficher le code du composant App , qui se trouve dans le fichier App.js du projet standard créé par create-react-app. Voici le code:

 import React, {Component} from "react" class App extends Component {   constructor() {       super()       this.state = {}   }     render() {       return (           <main>               <form>                   <input placeholder="First Name" /><br />                   <input placeholder="Last Name" /><br />                   <input placeholder="Age" /><br />                                     {/*       */}                   <br />                                     {/*          */}                   <br />                                     {/*        */}                   <br />                                     <button>Submit</button>               </form>               <hr />               <h2><font color="#3AC1EF">Entered information:</font></h2>               <p>Your name: {/*    */}</p>               <p>Your age: {/*  */}</p>               <p>Your gender: {/*  */}</p>               <p>Your destination: {/*   */}</p>               <p>                   Your dietary restrictions:                   {/*    */}               </p>           </main>       )   } } export default App 

En général, votre tâche consiste à vous assurer que les données que l'utilisateur saisit lors de l'utilisation des contrôles de formulaire apparaissent immédiatement dans le texte sous ce formulaire. Tirez parti de la technologie des composants gérés lorsque vous terminez la tâche. Il est à noter que la tâche qui vous est proposée est une version adaptée de cette tâche, vous pouvez donc y jeter un œil afin de mieux comprendre les fonctionnalités des contrôles que vous êtes invité à créer et configurer.

Voici ce que le composant affiche désormais à l'écran.


Application dans le navigateur

▍Solution


Vous pouvez aborder la solution du problème qui vous est proposé sous différents angles. Nous commencerons par mettre tout ce dont nous avons besoin dans l'état, après quoi nous mettrons en place les contrôles et autres mécanismes du composant.

Pour le moment, l'état du composant ressemblera à celui ci-dessous.

 this.state = {   firstName: "",   lastName: "",   age: 0,   gender: "",   destination: "",   dietaryRestrictions: [] } 

Il ne faut pas oublier que lors du travail sur un programme, il peut s'avérer, par exemple, qu'il sera plus pratique d'initialiser un état différemment. Si nous rencontrons quelque chose de similaire, nous changerons le code d'initialisation de l'état. En particulier, certains doutes peuvent maintenant être causés par le nombre 0 écrit dans la propriété age , dans lequel il est censé stocker l'âge entré par l'utilisateur. Peut-être faudra-t-il faire autrement avec le système de stockage de données de drapeau, qui est maintenant représenté par la propriété dietaryRestrictions , initialisée par un tableau vide.

Maintenant, après l'initialisation de l'état, prenons soin de configurer les contrôles. Étant donné que le code a déjà une description des champs de saisie - commençons par eux.

Ces contrôles devront être nommés en définissant leurs attributs de name afin qu'ils correspondent aux noms des propriétés d'état dans lesquelles les données entrées dans ces champs seront stockées. Ils doivent avoir un attribut value dont la valeur est déterminée en fonction des données stockées dans l'état. Lorsque vous saisissez des données dans chacun de ces champs, vous devez transmettre les données entrées au composant, ce qui onChange à disposer d'un onChange événements onChange . Toutes ces considérations conduisent au fait que la description des champs ressemble maintenant à ceci:

 <input   name="firstName"   value={this.state.firstName}   onChange={this.handleChange}   placeholder="First Name" /> <br /> <input   name="lastName"   value={this.state.lastName}   onChange={this.handleChange}   placeholder="Last Name" /> <br /> <input   name="age"   value={this.state.age}   onChange={this.handleChange}   placeholder="Age" /> 

En tant que méthode utilisée pour traiter les événements this.handleChange de ces champs, this.handleChange est toujours inexistant. Créez cette méthode:

 handleChange(event) {   const {name, value} = event.target   this.setState({       [name]: value   }) } 

Ici, nous extrayons les propriétés de name et de value de l'objet event.target , puis les utilisons pour définir la propriété d'état correspondante. Pour le moment, un tel code de gestionnaire d'événements universel nous conviendra, mais plus tard, lorsque nous travaillerons avec des indicateurs, nous y apporterons des modifications.

N'oubliez pas this liaison effectuée dans le constructeur du composant:

 this.handleChange = this.handleChange.bind(this) 

Afin d'obtenir une sortie au bas de la page de données entrées dans les champs firstName , secondName et age , secondName travaillerons avec les éléments <p> correspondants, en les amenant à la forme suivante:

 <p>Your name: {this.state.firstName} {this.state.lastName}</p> <p>Your age: {this.state.age}</p> 

Voyons maintenant ce que nous avons obtenu.


Application dans le navigateur

Comme vous pouvez le voir, dans le champ de saisie de l'âge, aucun indice ne s'affiche. Au lieu de cela, ce qui est défini dans la propriété state of age s'affiche, c'est-à-dire 0. Nous avons besoin d'un indice dans le champ vide. Essayons de remplacer la valeur de age in state par null . Après cela, il s'avère que le formulaire ressemble à ce qu'il devrait être, mais l'avertissement suivant s'affiche dans la console concernant le champ d' age :

 Warning: `value` prop on `input` should not be null. Consider using an empty string to clear the component or `undefined` for uncontrolled components 

Par conséquent, nous devrons remplacer la valeur de la propriété state age par une chaîne vide, ce qui apportera le code d'initialisation de l'état au format suivant:

 this.state = {   firstName: "",   lastName: "",   age: "",   gender: "",   destination: "",   dietaryRestrictions: [] } 

Essayez maintenant le formulaire. Immédiatement après l'ouverture, il aura la même apparence qu'au tout début du travail, c'est-à-dire que l'invite retournera dans le champ d' age . Lorsque vous remplissez les champs, les données saisies seront affichées en bas de la page.


Application dans le navigateur

Comme vous pouvez le voir, à ce stade du travail, tout fonctionne comme prévu.

Nous allons maintenant nous engager dans de nouveaux éléments. La prochaine étape du travail sur le formulaire consistera à y ajouter des commutateurs.

Enveloppez les commutateurs dans la <label> , ce qui nous permettra non seulement de signer le commutateur, mais également de nous assurer que le fait de cliquer sur cette signature, c'est-à-dire sur son élément parent, mène à sa sélection.

Lorsque vous travaillez avec des commutateurs, il convient de se rappeler qu'il s'agit d'une sorte de combinaison d'indicateurs avec l'attribut checked et les champs de texte qui ont l'attribut value . Les commutateurs forment un groupe dans lequel chacun des commutateurs porte le même nom, et la propriété checked des commutateurs est définie en fonction d'une condition configurée de sorte qu'il serait impossible d'activer plus d'un commutateur faisant partie du même groupe. onChange comme gestionnaire d'événements pour les commutateurs onChange .

Par conséquent, le code de description du commutateur ressemblera à ceci:

 <label>   <input       type="radio"       name="gender"       value="male"       checked={this.state.gender === "male"}       onChange={this.handleChange}   /> Male </label> <br /> <label>   <input       type="radio"       name="gender"       value="female"       checked={this.state.gender === "female"}       onChange={this.handleChange}   /> Female </label> 

Nous allons maintenant traiter l'élément <p> correspondant situé en bas de la page, comme suit:

 <p>Your gender: {this.state.gender}</p> 

Après cela, le formulaire peut être testé. Immédiatement après le démarrage, les deux commutateurs sont désélectionnés, car l'état stocke une valeur qui ne permet à aucune des vérifications effectuées lors de la définition de leur propriété checked de checked true . Après avoir cliqué sur l'un d'eux, la valeur correspondante tombe dans l'état (stockée dans l'attribut value du commutateur), le commutateur est sélectionné, le texte correspondant est affiché en bas du formulaire.


Application dans le navigateur

Maintenant, travaillons sur la zone de liste déroulante. Sa pièce ressemble à ceci:

 <select>   <option></option>   <option></option>   <option></option>   <option></option> </select> 

Ce code montre que nous prévoyons de décrire une zone de liste déroulante contenant quatre éléments.

La <select> et ses balises <option> ont un attribut value . Cependant, ces attributs ont des significations différentes. La valeur value affectée à l'élément <option> indique quelle devrait être la propriété d'état correspondante lorsque cet élément est sélectionné. Ce sont les lignes qui devraient figurer dans la liste déroulante. Dans notre cas, il s'agit de certaines destinations, par exemple des pays. Écrivons leurs noms avec une petite lettre afin que leur apparence corresponde aux valeurs des propriétés de value des autres éléments du code. Après cela, le code de la zone de liste déroulante ressemblera à ceci:

 <select value=>   <option value="germany">Germany</option>   <option value="norway">Norway</option>   <option value="north pole">North Pole</option>   <option value="south pole">South Pole</option> </select> 

Si nous parlons de l'attribut value de la <select> , alors aucune valeur codée en dur ne sera indiquée ici, mais un lien vers la propriété d'état correspondante:

 <select value={this.state.destination}>   <option value="germany">Germany</option>   <option value="norway">Norway</option>   <option value="north pole">North Pole</option>   <option value="south pole">South Pole</option> </select> 

Attribuez au champ d'autres attributs. En particulier, le nom correspondant au nom de la propriété dans l'état et le onChange événements this.handleChange , this.handleChange .

 <select   value={this.state.destination}   name="destination"   onChange={this.handleChange} >   <option value="germany">Germany</option>   <option value="norway">Norway</option>   <option value="north pole">North Pole</option>   <option value="south pole">South Pole</option> </select> 

Nous allons maintenant configurer la description de l'élément <p> , qui affichera ce qui est sélectionné dans le champ de destination :

 <p>Your destination: {this.state.destination}</p> 

Si vous regardez la page dans le navigateur en ce moment, vous pouvez voir que le premier élément de la liste est automatiquement sélectionné dans le champ, mais cela ne conduit évidemment pas à une mise à jour de l'état, car rien ne s'affiche après les deux-points dans la ligne Your destination: :.


Application dans le navigateur

Pour que la valeur de l' germany tombe dans l'état, vous devez ouvrir la zone de liste déroulante et sélectionner d'abord autre chose, puis sélectionner Germany .

Souvent, afin de prendre en compte cette caractéristique des champs de liste, dans leurs listes, en tant que premier élément, ils mettent quelque chose comme un élément avec une valeur vide et avec du texte comme -- Please Choose a destination -- . Dans notre cas, cela peut ressembler à ceci:

 <select   value={this.state.destination}   name="destination"   onChange={this.handleChange} >   <option value="">-- Please Choose a destination --</option>   <option value="germany">Germany</option>   <option value="norway">Norway</option>   <option value="north pole">North Pole</option>   <option value="south pole">South Pole</option> </select> 

Nous nous concentrerons sur cette option de configuration de la zone de liste déroulante.

Voyons maintenant, peut-être, la partie la plus difficile de notre tâche, qui est associée aux drapeaux. Ici, il convient d' dietaryRestrictions que la propriété d'état dietaryRestrictions , qui devrait être utilisée pour fonctionner avec des indicateurs, a été initialisée avec un tableau vide. Maintenant, quand il s'agit de travailler avec des contrôles, on a le sentiment qu'il vaudrait mieux représenter ce champ comme un objet. Il sera donc plus pratique de travailler avec des entités qui représentent des indicateurs individuels sous la forme de propriétés de cet objet avec des noms conviviaux, et non sous la forme d'éléments de tableau. Les propriétés de l'objet, qui seront désormais représentées par la dietaryRestrictions état dietaryRestrictions , contiendront des valeurs booléennes indiquant si la case à cocher correspondante est désactivée ( false ) ou cochée ( true ). Maintenant, le code d'initialisation d'état ressemblera à ceci:

 this.state = {   firstName: "",   lastName: "",   age: "",   gender: "",   destination: "",   dietaryRestrictions: {       isVegan: false,       isKosher: false,       isLactoseFree: false   } } 

Comme vous pouvez le voir, nous prévoyons de créer trois drapeaux. Tous, immédiatement après le chargement de la page, seront réinitialisés.

Nous décrivons les drapeaux dans le code renvoyé par le composant, en les enveloppant dans des balises <label> et en définissant leurs attributs. Voici à quoi ressemblera leur code:

 <label>   <input       type="checkbox"       name="isVegan"       onChange={this.handleChange}       checked={this.state.dietaryRestrictions.isVegan}   /> Vegan? </label> <br /> <label>   <input       type="checkbox"       name="isKosher"       onChange={this.handleChange}       checked={this.state.dietaryRestrictions.isKosher}   /> Kosher? </label> <br /> <label>   <input       type="checkbox"       name="isLactoseFree"       onChange={this.handleChange}       checked={this.state.dietaryRestrictions.isLactoseFree}   /> Lactose Free? </label> 

Les noms des propriétés de l'objet dietaryRestrictions ont été utilisés comme noms d'indicateur et les constructions de la forme this.state.dietaryRestrictions.isSomething comme valeurs de leurs attributs checked .

Veuillez noter que bien que le onChange déjà existant soit indiqué comme un gestionnaire d'événement this.handleChange onChange, nous devons apporter quelques modifications au programme pour nous assurer que le programme fonctionne correctement.

Jetez un œil à l'application.


Application dans le navigateur

Comme vous pouvez le voir, les drapeaux sur la page sont affichés, mais le composant ne contient pas encore tous les mécanismes nécessaires pour assurer leur bon fonctionnement. Voyons le gestionnaire d'événements.

Ici, pour travailler avec des cases à cocher, nous devons extraire event.target de l'objet, en plus de ceux déjà extraits, du type et des propriétés checked . Le premier est nécessaire pour vérifier le type de l'élément (les drapeaux sont du type représenté par la ligne de checkbox ), le second est de savoir si la case à cocher est cochée ou décochée. S'il s'avère que le gestionnaire a été appelé après que l'utilisateur a interagi avec l'indicateur, nous utilisons une procédure de définition d'état spéciale. Nous traiterons les événements des autres contrôles de la même manière qu'auparavant.

Lors de la mise à jour d'un état, il convient de garder à l'esprit que React est un système assez intelligent qui, si seulement une partie de l'état est mis à jour, combinera automatiquement dans le nouvel état ce qui est resté inchangé avec ce qui a changé. Mais on ne peut pas être sûr que le travail avec les propriétés des objets, qui sont les valeurs des propriétés d'état, sera effectué de la même manière. Nous allons vérifier cela en apportant le code handleChange au formulaire suivant. Ici, nous partons de l'hypothèse que les propriétés de l'objet dietaryRestrictions peuvent être modifiées une par une:

 handleChange(event) {   const {name, value, type, checked} = event.target   type === "checkbox" ?       this.setState({           dietaryRestrictions: {               [name]: checked           }       })   :   this.setState({       [name]: value   }) } 

Si vous ouvrez la page d'application dans un navigateur, puis immédiatement après l'avoir téléchargée, tout ira bien, lorsque vous essayez, par exemple, d'entrer un nom dans le champ First Name , tout fonctionnera également comme avant, mais lorsque vous essayez de définir l'une des cases à cocher, l'avertissement suivant sera émis :
Avertissement: Un composant modifie une case à cocher d'entrée contrôlée de type pour être non contrôlé. Les éléments d'entrée ne doivent pas passer de contrôlés à non contrôlés (ou vice versa). Décidez entre l'utilisation d'un élément d'entrée contrôlé ou non contrôlé pendant la durée de vie du composant. Plus d'informations: fb.me/react-controlled-components

Afin de mettre à jour correctement le contenu de l'objet dietaryRestrictions , vous pouvez utiliser le setState fonctionnel setState pour créer vous-même une nouvelle version de l'état. Si nous devions gérer un grand nombre de drapeaux, nous l'aurions probablement fait. Mais ici, nous ferons autrement. À savoir, nous allons créer les propriétés d' dietaryRestrictions objet dietaryRestrictions , en nous débarrassant de cet objet:

 this.state = {   firstName: "",   lastName: "",   age: "",   gender: "",   destination: "",   isVegan: false,   isKosher: false,   isLactoseFree: false } 

Nous allons maintenant modifier les paramètres des attributs des drapeaux, en dietaryRestrictions :

 <label>   <input       type="checkbox"       name="isVegan"       onChange={this.handleChange}       checked={this.state.isVegan}   /> Vegan? </label> <br /> <label>   <input       type="checkbox"       name="isKosher"       onChange={this.handleChange}       checked={this.state.isKosher}   /> Kosher? </label> <br /> <label>   <input       type="checkbox"       name="isLactoseFree"       onChange={this.handleChange}       checked={this.state.isLactoseFree}   /> Lactose Free? </label> 

Et enfin, éditez le code de l'élément qui affiche des informations sur les restrictions alimentaires spécifiées par l'utilisateur:

 <p>Your dietary restrictions:</p> <p>Vegan: {this.state.isVegan ? "Yes" : "No"}</p> <p>Kosher: {this.state.isKosher ? "Yes" : "No"}</p> <p>Lactose Free: {this.state.isLactoseFree ? "Yes" : "No"}</p> 

Après cela, nous vérifierons l'intégrité de l'application.


Application dans le navigateur

Comme vous pouvez le voir, tout fonctionne comme prévu.

Voici le code complet du composant App :

 import React, {Component} from "react" class App extends Component {   constructor() {       super()       this.state = {           firstName: "",           lastName: "",           age: "",           gender: "",           destination: "",           isVegan: false,           isKosher: false,           isLactoseFree: false       }       this.handleChange = this.handleChange.bind(this)   }     handleChange(event) {       const {name, value, type, checked} = event.target       type === "checkbox" ?           this.setState({               [name]: checked           })       :       this.setState({           [name]: value       })   }     render() {       return (           <main>               <form>                   <input                       name="firstName"                       value={this.state.firstName}                       onChange={this.handleChange}                       placeholder="First Name"                   />                   <br />                                     <input                       name="lastName"                       value={this.state.lastName}                       onChange={this.handleChange}                       placeholder="Last Name"                   />                   <br />                                     <input                       name="age"                       value={this.state.age}                       onChange={this.handleChange}                       placeholder="Age"                   />                   <br />                                     <label>                       <input                           type="radio"                           name="gender"                           value="male"                           checked={this.state.gender === "male"}                           onChange={this.handleChange}                       /> Male                   </label>                                     <br />                                     <label>                       <input                           type="radio"                           name="gender"                           value="female"                           checked={this.state.gender === "female"}                           onChange={this.handleChange}                       /> Female                   </label>                                     <br />                                     <select                       value={this.state.destination}                       name="destination"                       onChange={this.handleChange}                   >                       <option value="">-- Please Choose a destination --</option>                       <option value="germany">Germany</option>                       <option value="norway">Norway</option>                       <option value="north pole">North Pole</option>                       <option value="south pole">South Pole</option>                   </select>                                     <br />                                     <label>                       <input                           type="checkbox"                           name="isVegan"                           onChange={this.handleChange}                           checked={this.state.isVegan}                       /> Vegan?                   </label>                   <br />                                     <label>                       <input                           type="checkbox"                           name="isKosher"                           onChange={this.handleChange}                           checked={this.state.isKosher}                       /> Kosher?                   </label>                   <br />                                     <label>                       <input                           type="checkbox"                           name="isLactoseFree"                           onChange={this.handleChange}                           checked={this.state.isLactoseFree}                       /> Lactose Free?                   </label>                   <br />                                     <button>Submit</button>               </form>               <hr />               <h2><font color="#3AC1EF">Entered information:</font></h2>               <p>Your name: {this.state.firstName} {this.state.lastName}</p>               <p>Your age: {this.state.age}</p>               <p>Your gender: {this.state.gender}</p>               <p>Your destination: {this.state.destination}</p>               <p>Your dietary restrictions:</p>                             <p>Vegan: {this.state.isVegan ? "Yes" : "No"}</p>               <p>Kosher: {this.state.isKosher ? "Yes" : "No"}</p>               <p>Lactose Free: {this.state.isLactoseFree ? "Yes" : "No"}</p>                         </main>       )   } } export default App 

Résumé


Aujourd'hui, vous avez terminé les travaux pratiques sur les formulaires. Ensuite, vous avez répété ce que vous avez appris dans les cours précédents, et nous espérons que vous avez appris quelque chose de nouveau. La prochaine fois, nous parlerons de l'architecture des applications React.

Chers lecteurs! Dites-moi, a-t-il été difficile de terminer ce travail pratique?

Source: https://habr.com/ru/post/fr446208/


All Articles