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?
