Na parte de hoje da tradução do curso React, sugerimos que você conclua a próxima tarefa prática e apresente à sua atenção uma história sobre como modificar o estado dos componentes do React.

→
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 31. Oficina. Aplicação TODO. Estágio número 5
→
Original▍Job
Ao iniciar nosso aplicativo Todo, você pode perceber que uma notificação é exibida no console indicando que nós, configurando a propriedade
checked
de um elemento no componente
TodoItem
, não fornecemos um mecanismo para interagir com esse elemento na forma de um
onChange
eventos
onChange
. Ao trabalhar com a interface do aplicativo, isso resulta no fato de que os sinalizadores exibidos na página não podem ser verificados ou desmarcados.
Aqui você está convidado a equipar um elemento do tipo de
checkbox
de
checkbox
do componente
TodoItem
com um manipulador de eventos
TodoItem
, que, nesta fase do trabalho, é suficiente para apresentar na forma de uma função que gera algo para o console.
▍Solução
Aqui está a
TodoItem
código do componente
TodoItem
agora, armazenado no arquivo
TodoItem.js
:
import React from "react" function TodoItem(props) { return ( <div className="todo-item"> <input type="checkbox" checked={props.item.completed}/> <p>{props.item.text}</p> </div> ) } export default TodoItem
É isso que o console exibe quando o aplicativo é iniciado.
Notificação do consoleAo mesmo tempo, as bandeiras não respondem aos nossos efeitos.
Para se livrar dessa notificação e preparar o projeto para mais trabalhos, basta atribuir um
onChange
eventos
onChange
ao elemento
checkbox
. Aqui está o que parece no código:
import React from "react" function TodoItem(props) { return ( <div className="todo-item"> <input type="checkbox" checked={props.item.completed} onChange={() => console.log("Changed!")} /> <p>{props.item.text}</p> </div> ) } export default TodoItem
Aqui, como manipulador, usamos uma função simples que gera a palavra
Checked!
no console
Checked!
. Ao mesmo tempo, clicar nos sinalizadores não leva a uma alteração no estado deles, mas a notificação do console, como pode ser visto na figura a seguir, desaparece.
Os sinalizadores ainda não estão funcionando, mas a notificação do console desapareceuEssa pequena alteração feita no aplicativo nos permitirá, após lidarmos com a alteração no estado dos componentes, fazer com que as caixas de seleção funcionem corretamente.
Lição 32. Alterando o estado dos componentes
→
OriginalVamos começar com um aplicativo padrão criado usando
create-react-app
App.js
create-react-app
, no arquivo
App.js
que contém o seguinte código:
import React from "react" class App extends React.Component { constructor() { super() this.state = { count: 0 } } render() { return ( <div> <h1>{this.state.count}</h1> <button>Change!</button> </div> ) } } export default App
O
index.css
estilos
index.css
,
index.js
no arquivo
index.js
, contém a seguinte descrição de estilos:
div { display: flex; flex-direction: column; align-items: center; justify-content: center; } h1 { font-size: 3em; } button { border: 1px solid lightgray; background-color: transparent; padding: 10px; border-radius: 4px; } button:hover { cursor: pointer; } button:focus { outline:0; }
Nesse estágio, o aplicativo se parece com o mostrado na figura a seguir.
Página do aplicativo no navegadorHoje falaremos sobre como alterar o estado dos componentes. Se o componente tem um estado, isso permite, inicializando-o, armazenar alguns dados nele. Mas se o estado não pudesse ser alterado, o componente não se beneficiaria muito de sua presença, pois armazenar os dados não seria muito diferente de, por exemplo, copiá-los no código do componente.
Vamos falar sobre o aplicativo, no exemplo do qual consideraremos trabalhar com o estado do componente. O componente
App
cujo código é apresentado acima é um componente baseado em classe. Isso é óbvio, pois precisamos que esse componente tenha um estado. No código do componente, usamos o construtor.
Nele, como sempre, chamamos o método
super()
e inicializamos o estado escrevendo a propriedade
count
e atribuindo a ele um valor inicial de
0
. No método
render()
, imprimimos um cabeçalho de primeiro nível representando o valor da propriedade
count
do estado do componente, bem como um botão com a palavra
Change!
. Tudo isso é formatado usando estilos.
Se, nesta fase do trabalho no aplicativo, abra-o em um navegador e clique no botão, é claro que nada acontecerá. Mas precisamos clicar no botão para alterar o estado do componente, afetando sua propriedade
count
. Ao mesmo tempo, já estudamos a metodologia de processamento de eventos no React, e nossa tarefa é criar um mecanismo que, respondendo a um clique em um botão, altere a propriedade do estado de
count
.
Vamos resolver o problema equipando o botão com um
onClick
eventos
onClick
, que, para iniciantes, simplesmente produzirá algo no console.
Para fazer isso, adicionaremos um novo método à classe de componentes. Você pode chamá-lo como quiser, mas é costume chamar esses métodos para que seus nomes indiquem os eventos que estão processando. Como resultado, nós, como vamos usá-lo para processar o evento
click
, chamamos de
handleClick()
. Aqui está a aparência do código do componente do
App
.
import React from "react" class App extends React.Component { constructor() { super() this.state = { count: 0 } } handleClick() { console.log("I'm working!") } render() { return ( <div> <h1>{this.state.count}</h1> <button onClick={this.handleClick}>Change!</button> </div> ) } } export default App
Observe que, referindo-se a esse método a partir de
render()
, usamos uma construção do formulário
this.handleClick
.
Agora, se você clicar no botão, a mensagem correspondente aparecerá no console.
Clicar no botão chama o método de classe.Agora vamos fazê-lo para que clicar no botão aumente o número exibido acima, ou seja, modifique o estado do componente. Talvez tente alterar o estado do componente diretamente, no método
handleClick()
? Digamos que se reescrevemos esse método assim:
handleClick() { this.state.count++ }
Devo dizer imediatamente que isso não funciona com o estado dos componentes no React. Tentar executar esse código gerará um erro.
A condição do componente pode ser comparada com as roupas que uma pessoa veste. Se ele quer trocar de roupa, ele não altera ou repinta a roupa sem tirar a roupa, mas a tira e coloca outra coisa. Por uma questão de fato, é exatamente assim que eles trabalham com o estado dos componentes.
Você deve se lembrar de que estávamos falando de um método especial usado para modificar o estado, disponível em componentes baseados em classes devido ao fato de eles estenderem a classe
React.Component
. Este é o método
setState()
. É usado nos casos em que você precisa alterar o estado de um componente. Este método pode ser usado de diferentes maneiras.
Lembre-se de que um estado é um objeto. Vamos tentar passar para o método
setState()
um objeto que substituirá o estado.
handleClick()
o método
handleClick()
:
handleClick() { this.setState({ count: 1 }) }
Tentar usar esse método causará o seguinte erro:
TypeError: Cannot read property 'setState' of undefined
. De fato, o que estamos falando agora causa muita controvérsia entre os desenvolvedores do React, e agora vou mostrar uma maneira muito simples de resolver esse problema, que, à primeira vista, pode parecer incomum.
O ponto é que, sempre que, criando um método de classe (
handleClick()
no nosso caso), no qual está planejado usar o método
setState()
, esse método deve estar associado a
this
. Isso é feito no construtor. O código do componente após esta modificação terá a seguinte aparência:
import React from "react" class App extends React.Component { constructor() { super() this.state = { count: 0 } this.handleClick = this.handleClick.bind(this) } handleClick() { this.setState({ count: 1 }) } render() { return ( <div> <h1>{this.state.count}</h1> <button onClick={this.handleClick}>Change!</button> </div> ) } } export default App
Agora, depois de clicar no botão
Change!
o número 1 aparecerá acima, as mensagens de erro não serão exibidas.
Pressionar um botão modifica o estadoÉ verdade que o botão acabou sendo "único". Após o primeiro clique,
0
muda para
1
e, se você clicar novamente, nada acontecerá. Em geral, isso não é surpreendente. O código chamado quando o botão é clicado faz seu trabalho, cada vez que muda o estado para um novo, no entanto, após o primeiro clique no botão, o novo estado, no qual o número
1
é armazenado na propriedade
count
, não difere do antigo. Para resolver esse problema, considere outra maneira de trabalhar com o método
setState()
.
Se não estivermos interessados no que era o estado anterior do componente, podemos simplesmente passar um objeto para esse método, que substituirá o estado. Mas muitas vezes acontece que o novo estado de um componente depende do antigo. No nosso caso, isso significa que, com base no valor da propriedade
count
, que é armazenada na versão anterior do estado, queremos adicionar 1 a esse valor. Nos casos em que alterar o estado, você precisa estar ciente do que foi armazenado anteriormente nele, é possível transmitir ao método
setState()
uma função que, como parâmetro, recebe a versão anterior do estado. Você pode nomear esse parâmetro como quiser, no nosso caso, será
prevState
. A aquisição desta função terá a seguinte aparência:
handleClick() { this.setState(prevState => { }) }
Você pode pensar que, em tal função, basta referir-se ao estado usando uma construção da forma
this.state
, mas essa abordagem não nos convém. Portanto, é importante que essa função aceite a versão anterior do estado do componente.
A função deve retornar uma nova versão do estado. Aqui está a
handleClick()
método
handleClick()
para
handleClick()
esse problema:
handleClick() { this.setState(prevState => { return { count: prevState.count + 1 } }) }
Observe que, para obter o novo valor da propriedade
count
, usamos a construção
count: prevState.count + 1
. Você pode pensar que uma construção da
count: prevState.count++
formulários
count: prevState.count++
, mas o operador
++
count: prevState.count++
variável à qual é aplicada, isso significa uma tentativa de modificar a versão anterior do estado, portanto, não a usamos aqui.
O código completo do arquivo do componente nesta fase será semelhante a este:
import React from "react" class App extends React.Component { constructor() { super() this.state = { count: 0 } this.handleClick = this.handleClick.bind(this) } handleClick() { this.setState(prevState => { return { count: prevState.count + 1 } }) } render() { return ( <div> <h1>{this.state.count}</h1> <button onClick={this.handleClick}>Change!</button> </div> ) } } export default App
Agora, cada clique no botão aumenta o valor do contador.
Cada clique no botão aumenta o valor do contador.O que acabamos de descobrir abre grandes oportunidades para nós no desenvolvimento de aplicativos React.
Dissemos anteriormente que um componente pai pode, através de um mecanismo de propriedade, passar propriedades de seu próprio estado para componentes filhos. Se o React detectar uma alteração no estado do componente pai, ele renderizará novamente o componente filho para o qual esse estado é passado. Parece uma chamada para o método
render()
. Como resultado, o componente filho refletirá os novos dados armazenados no estado do componente pai.
Sumário
Hoje você preparou o aplicativo Todo para mais trabalhos sobre ele e também se familiarizou com os mecanismos usados no React para alterar o estado de um componente. Da próxima vez, você será solicitado a expandir os recursos do aplicativo de treinamento usando o que aprendeu hoje.
Caros leitores! Como você se sente sobre o fato de que o estado dos componentes no React não pode ser alterado diretamente sem o uso de mecanismos especiais?
