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?
