Tutorial Reagir Parte 25: Workshop sobre formulários

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

imagem

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 componentes
Parte 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 curso

Liçã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 navegador

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

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

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

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

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

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

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


All Articles