Tutorial React Parte 25: Taller sobre formularios

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

imagen

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 curso

Lecció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 navegador

Como 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 navegador

Como 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 navegador

Ahora 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 navegador

Para 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 navegador

Como 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 navegador

Como 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?

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


All Articles