En la parte de hoy de la traducción del curso de capacitación React, está invitado a completar una tarea de formulario.

→ 
Parte 1: descripción general del curso, razones de la popularidad de React, ReactDOM y JSX→ 
Parte 2: componentes funcionales→ 
Parte 3: archivos de componentes, estructura del proyecto→ 
Parte 4: componentes principales y secundarios→ 
Parte 5: inicio del trabajo en una aplicación TODO, los fundamentos del estilo→ 
Parte 6: sobre algunas características del curso, JSX y JavaScript→ 
Parte 7: estilos en línea→ 
Parte 8: trabajo continuo en la aplicación TODO, familiaridad con las propiedades de los componentes→ 
Parte 9: propiedades del componente→ 
Parte 10: Taller sobre trabajo con propiedades de componentes y estilo→ 
Parte 11: generación de marcado dinámico y método de matrices de mapas→ 
Parte 12: taller, tercera etapa de trabajo en una aplicación TODO→ 
Parte 13: componentes basados en clases→ 
Parte 14: taller sobre componentes basados en la clase, estado de los componentes.→ 
Parte 15: talleres de componentes de salud→ 
Parte 16: la cuarta etapa de trabajo en una aplicación TODO, manejo de eventos→ 
Parte 17: quinta etapa de trabajo en una aplicación TODO, modificando el estado de los componentes→ 
Parte 18: la sexta etapa de trabajo en una aplicación TODO→ 
Parte 19: métodos del ciclo de vida de los componentes.Parte 20: la primera lección de representación condicional→ 
Parte 21: segunda lección y taller sobre representación condicional→ 
Parte 22: la séptima etapa de trabajo en una aplicación TODO, descargando datos de fuentes externas→ 
Parte 23: primera lección sobre trabajar con formularios→ 
Parte 24: Segunda lección de formularios→ 
Parte 25: Taller sobre trabajo con formularios→ 
Parte 26: arquitectura de la aplicación, patrón de contenedor / componente→ 
Parte 27: proyecto del cursoLección 43. Taller. Trabajar con formularios
→ 
Original▍Trabajo
En esta práctica lección, está invitado a 
App.js el código del componente de la 
App , que se encuentra en el archivo 
App.js del proyecto estándar creado por create-react-app. Aquí está el código:
 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 general, su tarea es asegurarse de que los datos que ingrese el usuario mientras trabaja con los controles del formulario aparecen inmediatamente en el texto debajo de este formulario. Aproveche la tecnología de 
componentes administrados a medida que completa la tarea. Cabe señalar que la tarea que se le ofrece es una versión adaptada de 
esta tarea, por lo que puede echarle un vistazo para comprender mejor las características de los controles que está invitado a crear y configurar.
Esto es lo que el componente ahora muestra en la pantalla.
Aplicación en navegador▍Solución
Puede abordar la solución del problema que se le propone desde diferentes ángulos. Comenzaremos poniendo todo lo que necesitamos en el estado, luego de lo cual configuraremos los controles y otros mecanismos del componente.
Por el momento, el estado del componente se verá como se muestra a continuación.
 this.state = {   firstName: "",   lastName: "",   age: 0,   gender: "",   destination: "",   dietaryRestrictions: [] } 
Debe tenerse en cuenta que en el proceso de trabajar en un programa puede resultar que, por ejemplo, será más conveniente inicializar un estado de manera diferente. Si nos encontramos con algo similar, cambiaremos el código de inicialización del estado. En particular, ahora algunas dudas pueden ser causadas por el número 0 escrito en la propiedad 
age , en el que se supone que almacena la edad ingresada por el usuario. Tal vez, será necesario hacer lo contrario con el sistema de almacenamiento de datos del indicador, que ahora está representado por la propiedad 
dietaryRestrictions , inicializada por una matriz vacía.
Ahora, después de la inicialización del estado, ocupémonos de configurar los controles. Como el código ya tiene una descripción de los campos de entrada, comencemos con ellos.
Estos controles deberán recibir nombres configurando sus atributos de 
name para que coincidan con los nombres de las propiedades de estado en las que se almacenarán los datos ingresados en estos campos. Deben tener un atributo de 
value cuyo valor se determina en función de los datos almacenados en el estado. Al ingresar datos en cada uno de estos campos, debe pasar los datos ingresados al componente, lo que lleva a la necesidad de que tengan un 
onChange eventos 
onChange . Todas estas consideraciones conducen al hecho de que la descripción de los campos ahora se ve así:
 <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" /> 
Como método utilizado para procesar los eventos 
onChange de estos campos, 
this.handleChange aún no existe. Crea este método:
 handleChange(event) {   const {name, value} = event.target   this.setState({       [name]: value   }) } 
Aquí extraemos las propiedades de 
name y 
value del objeto 
event.target , y luego las usamos para establecer la propiedad de estado correspondiente. Por el momento, un código de controlador de eventos tan universal nos conviene, pero más tarde, cuando empecemos a trabajar con banderas, haremos cambios en él.
No olvide el enlace realizado en el constructor del componente:
 this.handleChange = this.handleChange.bind(this) 
Para lograr la salida en la parte inferior de la página de datos ingresados en 
age campos 
firstName , 
secondName y 
age , trabajaremos con los elementos 
<p> correspondientes, llevándolos a la siguiente forma:
 <p>Your name: {this.state.firstName} {this.state.lastName}</p> <p>Your age: {this.state.age}</p> 
Ahora echemos un vistazo a lo que tenemos.
Aplicación en navegadorComo puede ver, en el campo para ingresar la edad, no se muestra una pista. En cambio, se muestra lo que se establece en la propiedad estatal de 
age , es decir, 0. Necesitamos una pista en el campo vacío. Intentemos reemplazar el valor de 
age en estado por 
null . Después de eso, resulta que el formulario se ve como debería, pero la siguiente advertencia se muestra en la consola con respecto al campo de 
age :
 Warning: `value` prop on `input` should not be null. Consider using an empty string to clear the component or `undefined` for uncontrolled components 
Como resultado, tendremos que reemplazar el valor de la propiedad de estado de 
age con una cadena vacía, llevando el código de inicialización de estado a la siguiente forma:
 this.state = {   firstName: "",   lastName: "",   age: "",   gender: "",   destination: "",   dietaryRestrictions: [] } 
Ahora prueba el formulario. Inmediatamente después de la apertura, se verá igual que al comienzo del trabajo, es decir, el aviso volverá al campo de 
age . Al completar los campos, los datos ingresados se mostrarán en la parte inferior de la página.
Aplicación en navegadorComo puede ver, en esta etapa del trabajo, todo funciona como se esperaba.
Ahora nos dedicaremos a nuevos elementos. El siguiente paso para trabajar en el formulario será agregarle modificadores.
Envuelva los interruptores en la 
<label> , lo que nos permitirá no solo firmar el interruptor, sino también para asegurarnos de que al hacer clic en esta firma, es decir, en su elemento padre, conduzca a su selección.
Al trabajar con interruptores, vale la pena recordar que son una especie de combinación de banderas con el atributo 
checked y los campos de texto que tienen el atributo de 
value . Los conmutadores forman un grupo en el que a cada uno de los conmutadores se les asigna el mismo nombre, y la propiedad 
checked de los conmutadores se establece de acuerdo con una condición que está configurada de modo que sería imposible encender más de un conmutador que sea parte del mismo grupo. 
onChange como el controlador de eventos para los conmutadores 
onChange .
Como resultado, el código de descripción del interruptor se verá así:
 <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> 
Ahora procesaremos el elemento 
<p> correspondiente ubicado en la parte inferior de la página, de la siguiente manera:
 <p>Your gender: {this.state.gender}</p> 
Después de eso, el formulario puede ser probado. Inmediatamente después del inicio, ambos conmutadores no están seleccionados, ya que un estado se almacena en un valor que no permite que ninguna de las comprobaciones realizadas al configurar su propiedad 
checked true . Después de hacer clic en uno de ellos, el valor correspondiente cae en el estado (almacenado en el atributo de 
value del interruptor), se selecciona el interruptor y el texto correspondiente se muestra en la parte inferior del formulario.
Aplicación en navegadorAhora trabajemos en el cuadro combinado. Su pieza de trabajo se ve así:
 <select>   <option></option>   <option></option>   <option></option>   <option></option> </select> 
Este código muestra que planeamos describir un cuadro combinado que contiene cuatro elementos.
La etiqueta 
<select> y sus etiquetas 
<option> tienen un atributo de 
value . Sin embargo, estos atributos tienen diferentes significados. El valor del 
value asignado al elemento 
<option> indica cuál debería ser la propiedad de estado correspondiente cuando se selecciona este elemento. Estas son las líneas que deberían estar en la lista desplegable. En nuestro caso, estos son ciertos destinos, por ejemplo, países. Escribamos sus nombres con una letra minúscula para que su apariencia corresponda a los valores de las propiedades de 
value de otros elementos en el código. Después de eso, el código para el cuadro combinado se verá así:
 <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 hablamos sobre el atributo de 
value de la 
<select> , no se indicará aquí ningún valor codificado, sino un enlace a la propiedad de estado correspondiente:
 <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> 
Asigne al campo otros atributos. En particular, el nombre correspondiente al nombre de la propiedad en estado y el 
onChange eventos 
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> 
Ahora configuraremos la descripción del elemento 
<p> , que mostrará lo que está seleccionado en el campo de 
destination :
 <p>Your destination: {this.state.destination}</p> 
Si mira la página en el navegador en este momento, puede ver que el primer elemento de la lista se selecciona automáticamente en el campo, pero esto, obviamente, no conduce a una actualización del estado, ya que no se muestra nada después de los dos puntos en la línea 
Your destination:Aplicación en navegadorPara que el valor de 
germany caiga en el estado, debe abrir el cuadro combinado y seleccionar primero algo más, y luego seleccionar 
Germany .
A menudo, para tener en cuenta esta característica de los campos de lista, en sus listas, como primer elemento, colocan algo así como un elemento con un valor vacío y con un texto como 
-- Please Choose a destination -- . En nuestro caso, puede verse así:
 <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> 
Nos centraremos en esta opción de configurar el cuadro combinado.
Ahora tratemos, quizás, la parte más difícil de nuestra tarea, que está asociada con las banderas. Aquí vale la pena 
dietaryRestrictions que la propiedad del estado 
dietaryRestrictions , que se planea utilizar para trabajar con banderas, se inicializó con una matriz vacía. Ahora, cuando se trata de trabajar con controles, existe la sensación de que sería mejor representar este campo como un objeto. Por lo tanto, será más conveniente trabajar con entidades que representan banderas individuales en forma de propiedades de este objeto con nombres descriptivos, y no en forma de elementos de matriz. Las propiedades del objeto, que ahora estarán representadas por la 
dietaryRestrictions estado 
dietaryRestrictions , contendrán valores booleanos que indican si la casilla de verificación correspondiente está desactivada ( 
false ) o marcada ( 
true ). Ahora el código de inicialización del estado se verá así:
 this.state = {   firstName: "",   lastName: "",   age: "",   gender: "",   destination: "",   dietaryRestrictions: {       isVegan: false,       isKosher: false,       isLactoseFree: false   } } 
Como puede ver, planeamos crear tres banderas. Todos ellos, inmediatamente después de cargar la página, se restablecerán.
Describimos las banderas en el código devuelto por el componente, envolviéndolas en 
<label> y configurando sus atributos. Así es como se verá su código:
 <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> 
Los nombres de los indicadores utilizados son nombres de propiedad del objeto 
dietaryRestrictions , y los valores de sus atributos 
this.state.dietaryRestrictions.isSomething son construcciones de la forma 
this.state.dietaryRestrictions.isSomething .
Tenga en cuenta que aunque el 
onChange ya existente se indica como un controlador de evento de 
this.handleChange , debemos realizar algunos cambios en el programa para asegurarnos de que funciona correctamente.
Echa un vistazo a la aplicación.
Aplicación en navegadorComo puede ver, se muestran los indicadores en la página, pero el componente aún no contiene todos los mecanismos necesarios para garantizar su correcto funcionamiento. Tratemos con el controlador de eventos.
Aquí, para trabajar con casillas de verificación, necesitamos extraer 
event.target del objeto, además de los ya extraídos, el 
type y las propiedades 
checked . El primero es necesario para verificar el tipo de elemento (las banderas son del tipo representado por la línea de la 
checkbox de 
checkbox ), el segundo es averiguar si la casilla de verificación está marcada o desmarcada. Si resulta que se llamó al controlador después de que el usuario interactuó con el indicador, usamos un procedimiento de configuración de estado especial. Manejaremos los eventos de otros controles de la misma manera que antes.
Al actualizar un estado, debe tenerse en cuenta que React es un sistema bastante inteligente que, si solo se actualiza parte del estado, combinará automáticamente en el nuevo estado lo que ha permanecido sin cambios con lo que ha cambiado. Pero no se puede estar seguro de que el trabajo con las propiedades de los objetos, que son los valores de las propiedades de estado, se llevará a cabo de la misma manera. Verificaremos esto llevando el código 
handleChange al siguiente formulario. Aquí procedemos de la suposición de que las propiedades del objeto 
dietaryRestrictions se pueden cambiar de una en una:
 handleChange(event) {   const {name, value, type, checked} = event.target   type === "checkbox" ?       this.setState({           dietaryRestrictions: {               [name]: checked           }       })   :   this.setState({       [name]: value   }) } 
Si abre la página de la aplicación en un navegador, inmediatamente después de descargarla, todo se verá bien, cuando intente, por ejemplo, ingresar un nombre en el campo 
First Name , todo funcionará como antes, pero cuando intente configurar una de las casillas de verificación, se emitirá la siguiente advertencia :
Advertencia: un componente está cambiando una entrada controlada de tipo casilla de verificación para que no esté controlada. Los elementos de entrada no deben cambiar de controlado a no controlado (o viceversa). Decida entre usar un elemento de entrada controlado o no controlado durante la vida útil del componente. Más información: fb.me/react-controlled-components
Para actualizar correctamente el contenido del objeto 
dietaryRestrictions , puede usar el 
setState funcional 
setState para crear una nueva versión del estado usted mismo. Si tuviéramos que gestionar una gran cantidad de banderas, entonces probablemente lo habríamos hecho. Pero aquí haremos lo contrario. A saber, hacemos las propiedades de las propiedades de 
dietaryRestrictions objeto 
dietaryRestrictions este objeto:
 this.state = {   firstName: "",   lastName: "",   age: "",   gender: "",   destination: "",   isVegan: false,   isKosher: false,   isLactoseFree: false } 
Ahora cambiaremos la configuración de los atributos de las banderas, 
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> 
Y finalmente, edite el código del elemento que muestra información sobre las restricciones dietéticas especificadas por el usuario:
 <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> 
Después de eso, verificaremos el estado de la aplicación.
Aplicación en navegadorComo puede ver, todo funciona como se esperaba.
Aquí está el código completo del componente de la 
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 
Resumen
Hoy ha completado el trabajo práctico en los formularios. Luego repitió lo que aprendió en las clases anteriores, y esperamos que haya aprendido algo nuevo. La próxima vez hablaremos sobre la arquitectura de las aplicaciones React.
Estimados lectores! Dime, ¿fue difícil completar este trabajo práctico?
