Na parte atual da tradução do curso de treinamento do React, você está convidado a concluir uma tarefa do formulário.

→ 
Parte 1: visão geral do curso, razões para a popularidade do React, ReactDOM e JSX→ 
Parte 2: componentes funcionais→ 
Parte 3: arquivos de componentes, estrutura do projeto→ 
Parte 4: componentes pai e filho→ 
Parte 5: início do trabalho em um aplicativo TODO, noções básicas de estilo→ 
Parte 6: sobre alguns recursos do curso, JSX e JavaScript→ 
Parte 7: estilos embutidos→ 
Parte 8: trabalho contínuo na aplicação TODO, familiaridade com as propriedades dos componentes→ 
Parte 9: propriedades do componente→ 
Parte 10: Workshop sobre como trabalhar com propriedades e estilo de componentes→ 
Parte 11: geração dinâmica de marcação e método de matrizes de mapas→ 
Parte 12: workshop, terceira etapa do trabalho em uma aplicação TODO→ 
Parte 13: componentes baseados em classe→ 
Parte 14: workshop sobre componentes baseados em classe, status dos componentes→ 
Parte 15: oficinas de saúde componentes→ 
Parte 16: a quarta etapa do trabalho em um aplicativo TODO, manipulação de eventos→ 
Parte 17: quinta etapa do trabalho em um aplicativo TODO, modificando o estado dos componentes→ 
Parte 18: a sexta etapa do trabalho em um aplicativo TODO→ 
Parte 19: métodos do ciclo de vida dos componentesParte 20: a primeira lição sobre renderização condicional→ 
Parte 21: segunda lição e workshop sobre renderização condicional→ 
Parte 22: sétima etapa do trabalho em um aplicativo TODO, baixando dados de fontes externas→ 
Parte 23: primeira lição sobre como trabalhar com formulários→ 
Parte 24: Segunda lição sobre formulários→ 
Parte 25: Workshop sobre como trabalhar com formulários→ 
Parte 26: arquitetura do aplicativo, padrão Container / Component→ 
Parte 27: projeto do cursoLição 43. Oficina. Trabalhar com formulários
→ 
Original▍Job
Nesta lição prática, você está convidado a exibir o código do componente 
App , localizado no arquivo 
App.js do projeto padrão criado por create- 
App.js -app. Aqui está o 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 
Em geral, sua tarefa é garantir que os dados inseridos pelo usuário ao trabalhar com os controles do formulário apareçam imediatamente no texto abaixo deste formulário. Aproveite a tecnologia de 
componentes gerenciados ao concluir a tarefa. Deve-se observar que a tarefa oferecida a você é uma versão adaptada 
dessa tarefa, para que você possa dar uma olhada para entender melhor os recursos dos controles que você está convidado a criar e configurar.
Aqui está o que o componente agora exibe na tela.
Aplicativo no navegador▍Solução
Você pode abordar a solução do problema proposto a você de diferentes ângulos. Começaremos colocando tudo o que precisamos no estado, após o qual configuraremos os controles e outros mecanismos do componente.
No momento, o estado do componente será exibido como mostrado abaixo.
 this.state = {   firstName: "",   lastName: "",   age: 0,   gender: "",   destination: "",   dietaryRestrictions: [] } 
Deve-se ter em mente que, no processo de trabalhar em um programa, pode acontecer que, por exemplo, seja mais conveniente inicializar um estado de maneira diferente. Se encontrarmos algo semelhante, mudaremos o código de inicialização do estado. Em particular, agora algumas dúvidas podem ser causadas pelo número 0 escrito na propriedade 
age , na qual é suposto armazenar a idade inserida pelo usuário. Talvez seja necessário fazer o contrário com o sistema de armazenamento de dados do sinalizador, que agora é representado pela propriedade 
dietaryRestrictions , inicializada por uma matriz vazia.
Agora, após a inicialização do estado, retomaremos a configuração dos controles. Como o código já tem uma descrição dos campos de entrada - vamos começar com eles.
Esses controles precisarão receber nomes, definindo seus atributos de 
name para que correspondam aos nomes das propriedades do estado nas quais os dados inseridos nesses campos serão armazenados. Eles devem ter um atributo 
value cujo valor seja determinado com base nos dados armazenados no estado. Ao inserir dados em cada um desses campos, você precisa passar os dados inseridos para o componente, o que leva à necessidade de que eles tenham um 
onChange eventos 
onChange . Todas essas considerações levam ao fato de que a descrição dos campos agora se parece com isso:
 <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 um método usado para processar os eventos 
onChange desses campos, 
this.handleChange ainda não existe. Crie este método:
 handleChange(event) {   const {name, value} = event.target   this.setState({       [name]: value   }) } 
Aqui, extraímos as propriedades de 
name e 
value do objeto 
event.target e as usamos para definir a propriedade de estado correspondente. No momento, esse código universal de manipulador de eventos nos convém, mas mais tarde, quando começarmos a trabalhar com sinalizadores, faremos alterações nele.
Não se esqueça da ligação realizada no construtor de componentes:
 this.handleChange = this.handleChange.bind(this) 
Para obter resultados na parte inferior da página de dados inseridos nos campos 
firstName , 
secondName e 
age , trabalharemos com os elementos 
<p> correspondentes, trazendo-os para o seguinte formato:
 <p>Your name: {this.state.firstName} {this.state.lastName}</p> <p>Your age: {this.state.age}</p> 
Agora vamos dar uma olhada no que conseguimos.
Aplicativo no navegadorComo você pode ver, no campo para inserir a idade, uma dica não é exibida. Em vez disso, o que é definido na propriedade state of 
age é exibido, ou seja, 0. Precisamos de uma dica no campo vazio. Vamos tentar substituir o valor da 
age no estado por 
null . Depois disso, verifica-se que o formulário tem a aparência que deveria, mas o seguinte aviso é exibido no console em relação ao 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, precisaremos substituir o valor da propriedade 
age state por uma string vazia, trazendo o código de inicialização do estado para o seguinte formato:
 this.state = {   firstName: "",   lastName: "",   age: "",   gender: "",   destination: "",   dietaryRestrictions: [] } 
Agora tente o formulário. Imediatamente após a abertura, ele terá a mesma aparência do início do trabalho, ou seja, o prompt retornará ao campo de 
age . Ao preencher os campos, os dados inseridos serão exibidos na parte inferior da página.
Aplicativo no navegadorComo você pode ver, nesta fase do trabalho, tudo funciona como esperado.
Agora estaremos envolvidos em novos elementos. A próxima etapa do trabalho no formulário será adicionar opções a ele.
Coloque as opções na 
<label> , o que permitirá não apenas assinar a opção, mas também garantir que clicar nessa assinatura, ou seja, em seu elemento pai, leve à sua seleção.
Ao trabalhar com comutadores, vale lembrar que eles são uma espécie de combinação de sinalizadores com o atributo 
checked e os campos de texto que possuem o atributo 
value . Os comutadores formam um grupo no qual cada um dos comutadores recebe o mesmo nome e a propriedade 
checked dos comutadores é definida de acordo com uma condição configurada para que seria impossível ativar mais de um comutador que faz parte do mesmo grupo. 
onChange como o manipulador de eventos para os comutadores 
onChange .
Como resultado, o código de descrição do comutador ficará assim:
 <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> 
Agora, processaremos o elemento 
<p> correspondente localizado na parte inferior da página, da seguinte maneira:
 <p>Your gender: {this.state.gender}</p> 
Depois disso, o formulário pode ser testado. Imediatamente após o início, as duas opções não são selecionadas, pois um estado é armazenado em um valor que não permite que nenhuma das verificações executadas ao configurar sua propriedade 
checked true . Após clicar em um deles, o valor correspondente cai no estado (armazenado no atributo 
value do comutador), o comutador é selecionado e o texto correspondente é exibido na parte inferior do formulário.
Aplicativo no navegadorAgora vamos trabalhar na caixa de combinação. Sua peça de trabalho é assim:
 <select>   <option></option>   <option></option>   <option></option>   <option></option> </select> 
Este código mostra que planejamos descrever uma caixa de combinação contendo quatro itens.
A tag 
<select> e suas tags 
<option> têm um atributo 
value . No entanto, esses atributos têm significados diferentes. O valor do 
value atribuído ao elemento 
<option> indica qual deve ser a propriedade do estado correspondente quando esse elemento é selecionado. Essas são as linhas que devem estar na lista suspensa. No nosso caso, esses são alguns destinos, por exemplo, países. Vamos escrever seus nomes com uma letra minúscula para que sua aparência corresponda aos valores das propriedades de 
value de outros elementos no código. Depois disso, o código da caixa de combinação ficará assim:
 <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> 
Se falarmos sobre o atributo 
value da 
<select> , então não será indicado algum valor codificado aqui, mas um link para a propriedade de estado correspondente:
 <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> 
Atribua ao campo outros atributos. Em particular, o nome correspondente ao nome da propriedade no estado e o 
onChange eventos 
onChange , 
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> 
Agora vamos configurar a descrição do elemento 
<p> , que exibirá o que está selecionado no campo de 
destination :
 <p>Your destination: {this.state.destination}</p> 
Se você olhar a página no navegador agora, poderá ver que o primeiro elemento da lista é selecionado automaticamente no campo, mas isso, obviamente, não leva a uma atualização do estado, pois nada é exibido após os dois pontos na linha 
Your destination: .
Aplicativo no navegadorPara que o valor da 
germany caia no estado, é necessário abrir a caixa de combinação e primeiro selecionar outra coisa e, em seguida, selecionar 
Germany .
Freqüentemente, para levar em conta esse recurso dos campos de lista, em suas listas, como primeiro elemento, eles colocam algo como um elemento com um valor vazio e com texto como 
-- Please Choose a destination -- . No nosso caso, pode ser assim:
 <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> 
Vamos nos concentrar nessa opção de definir a caixa de combinação.
Agora vamos lidar com, talvez, a parte mais difícil da nossa tarefa, que está associada a sinalizadores. Aqui vale a pena 
dietaryRestrictions que a propriedade state 
dietaryRestrictions , planejada para ser usada para trabalhar com sinalizadores, foi inicializada com uma matriz vazia. Agora, quando se trata de trabalhar com controles, existe a sensação de que seria melhor representar esse campo como um objeto. Portanto, será mais conveniente trabalhar com entidades que representam sinalizadores individuais na forma de propriedades desse objeto com nomes amigáveis, e não na forma de elementos de matriz. As propriedades do objeto, que agora serão representadas pela 
dietaryRestrictions estado 
dietaryRestrictions , conterão valores booleanos indicando se a caixa de seleção correspondente está limpa ( 
false ) ou marcada ( 
true ). Agora o código de inicialização do estado ficará assim:
 this.state = {   firstName: "",   lastName: "",   age: "",   gender: "",   destination: "",   dietaryRestrictions: {       isVegan: false,       isKosher: false,       isLactoseFree: false   } } 
Como você pode ver, planejamos criar três sinalizadores. Todos eles, imediatamente após o carregamento da página, serão redefinidos.
Descrevemos os sinalizadores no código retornado pelo componente, agrupando-os em tags 
<label> e definindo seus atributos. Aqui está a aparência do 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> 
Os nomes dos sinalizadores usados são nomes de propriedades do objeto 
dietaryRestrictions e os valores de seus atributos 
checked são construções no formato 
this.state.dietaryRestrictions.isSomething .
Observe que, embora o 
onChange já existente seja indicado como um manipulador de eventos de 
this.handleChange , precisamos fazer algumas alterações no programa para garantir que o programa funcione corretamente.
Dê uma olhada no aplicativo.
Aplicativo no navegadorComo você pode ver, os sinalizadores na página são exibidos, mas o componente ainda não contém todos os mecanismos necessários para garantir o funcionamento correto. Vamos lidar com o manipulador de eventos.
Aqui, para trabalhar com caixas de seleção, precisamos extrair 
event.target do objeto, além dos já extraídos, do 
type e das propriedades 
checked . O primeiro é necessário para verificar o tipo do elemento (os sinalizadores são do tipo representado pela linha da 
checkbox ); o segundo é descobrir se a caixa de seleção está marcada ou desmarcada. Se o manipulador tiver sido chamado após o usuário interagir com o sinalizador, usaremos um procedimento especial de configuração de estado. Lidaremos com os eventos de outros controles da mesma maneira que antes.
Ao atualizar um estado, deve-se ter em mente que o React é um sistema bastante inteligente que, se apenas uma parte do estado for atualizada, combinará automaticamente no novo estado o que permaneceu inalterado com o que mudou. Mas não se pode ter certeza de que o trabalho com as propriedades dos objetos, que são os valores das propriedades do estado, será realizado da mesma maneira. Verificaremos isso trazendo o código 
handleChange para o seguinte formulário. Aqui procedemos da suposição de que as propriedades do objeto 
dietaryRestrictions podem ser alteradas uma de cada vez:
 handleChange(event) {   const {name, value, type, checked} = event.target   type === "checkbox" ?       this.setState({           dietaryRestrictions: {               [name]: checked           }       })   :   this.setState({       [name]: value   }) } 
Se você abrir a página do aplicativo em um navegador e, imediatamente após o download, tudo ficará bem; quando você tentar, por exemplo, inserir um nome no campo 
First Name , tudo funcionará como antes, mas quando você tentar definir uma das caixas de seleção, o seguinte aviso será emitido :
Aviso: Um componente está alterando uma caixa de seleção entrada controlada do tipo para não ser controlada. Os elementos de entrada não devem mudar de controlado para não controlado (ou vice-versa). Decida entre usar um elemento de entrada controlado ou não controlado durante a vida útil do componente. Mais informações: fb.me/react-controlled-components
Para atualizar corretamente o conteúdo do objeto 
dietaryRestrictions , você pode usar o 
setState funcional 
setState para criar uma nova versão do estado. Se tivéssemos que gerenciar um grande número de sinalizadores, provavelmente o teríamos feito. Mas aqui faremos o contrário. Ou seja, 
dietaryRestrictions as propriedades das propriedades do 
dietaryRestrictions objeto 
dietaryRestrictions , eliminando este objeto:
 this.state = {   firstName: "",   lastName: "",   age: "",   gender: "",   destination: "",   isVegan: false,   isKosher: false,   isLactoseFree: false } 
Agora vamos alterar as configurações dos atributos dos sinalizadores, eliminando as 
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> 
E, finalmente, edite o código do elemento que exibe informações sobre as restrições alimentares especificadas pelo usuário:
 <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> 
Depois disso, verificaremos a integridade do aplicativo.
Aplicativo no navegadorComo você pode ver, tudo funciona como esperado.
Aqui está o código completo do componente 
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 
Sumário
Hoje você concluiu o trabalho prático dos formulários. Então você repetiu o que aprendeu nas aulas anteriores e esperamos que você tenha aprendido algo novo. Da próxima vez, falaremos sobre a arquitetura dos aplicativos React.
Caros leitores! Diga-me, foi difícil concluir este trabalho prático?
