
Bom dia amigos!
O gancho useState () gerencia o estado nos componentes funcionais do React. Em beans de classe, o estado é armazenado em this.state e o método this.setState () é chamado para atualizar.
Normalmente, não há nada difícil em trabalhar com o estado. No entanto, há uma nuance importante associada à atualização.
Como o estado é atualizado: imediatamente (de forma síncrona) ou diferido (de forma assíncrona)? Continue lendo para descobrir a resposta.
1. Atualizando o estado com useState ()
Digamos que temos esse componente funcional:
import { useState } from 'react'
function DoubleIncreaser() {
const [count, setCount] = useState(0)
const doubleIncreaseHandler = () => {
setCount(count + 1)
setCount(count + 1)
}
return (
<>
<button onClick={doubleIncreaseHandler}>
Double Increase
</button>
<div>Count: {count}</div>
</>
)
}
const [count, setCount] = useState (0) define o estado inicial do componente. count é uma variável que contém o estado atual e setCount é uma função para atualizar esse estado.
O componente contém um botão de aumento duplo. Quando este botão é clicado, o manipulador doubleIncreaseHandler é chamado, realizando duas atualizações sucessivas para contar: setCount (contagem + 1) e então setCount (contagem + 1) novamente.
Qual será o estado do componente após clicar no botão 1 ou 2?
Abra esta demonstração e clique no botão. O valor da contagem aumentará em 1 após cada clique.
Quando setCount (count + 1) atualiza o estado, o valor de contagem não muda imediatamente. Em vez disso, o React agenda o estado a ser atualizado e, na próxima vez em que for renderizado, em const [count, setCount] = useState (0), o gancho atribui um novo valor para contar.
Por exemplo: se o valor da variável count for 0, chame setCount (count + 1); setCount (count + 1) avalia para setCount (0 + 1); setCount (0 + 1) - que resulta em 1 como o valor do estado na próxima renderização.
Portanto, a atualização do estado usando setValue (newValue) em [value, setValue] = useState () é feita de forma assíncrona.
No entanto, a função de atualização de estado pode receber um retorno de chamada como um argumento para calcular um novo estado com base no atual. No nosso caso, podemos usar setCount (actualCount => actualCount + 1):
import { useState } from 'react'
function DoubleIncreaser() {
const [count, setCount] = useState(0)
const doubleIncreaseHandler = () => {
setCount(actualCount => actualCount + 1)
setCount(actualCount => actualCount + 1)
}
return (
<>
<button onClick={doubleIncreaseHandler}>
Double Increase
</button>
<div>Count: {count}</div>
</>
)
}
Ao atualizar o estado usando essa função, o argumento actualCount conterá o valor do estado real.
Abra esta demonstração e clique no botão. A contagem aumentará para 2 conforme o esperado.
Claro, sempre podemos criar uma variável intermediária:
import { useState } from 'react'
function DoubleIncreaser() {
const [count, setCount] = useState(0)
const doubleIncrease = () => {
let actualCount = count
actualCount = actualCount + 1
actualCount = actualCount + 1
setCount(actualCount)
}
return (
<>
<button onClick={this.doubleIncrease}>
Double Increase
</button>
<div>Count: {count}</div>
</>
)
}
let actualCount = count é uma variável intermediária que pode ser atualizada como desejar. Esta variável é usada para atualizar o estado usando setCount (actualCount).
2. O estado é imutável (imutável) e somente leitura
Se você esquecer que o estado é atualizado na próxima renderização, você pode tentar ler o valor imediatamente após alterá-lo. Infelizmente, você não receberá nada:
function FetchUsers() {
const [users, setUsers] = useState([])
useEffect(() => {
const startFetching = async () => {
const response = await fetch('/users')
const fetchedUsers = await response.json()
setUsers(fetchedUsers)
console.log(users) // => []
console.log(fetchedUsers) // => ['John', 'Jane', 'Alice', 'Bob']
}
startFetching()
}, [])
return (
<ul>
{users.map(user => <li>{user}</li>)}
</ul>
)
}
O componente FetchUsers envia uma solicitação de montagem - startFetching ().
Quando os dados são recebidos, setUsers (fetchedUsers) atualiza o estado. No entanto, as mudanças não acontecem da noite para o dia.
A variável de usuários é imutável e somente leitura. Apenas o gancho useState () pode atribuir um novo valor a ele. Você não pode fazer isso diretamente:
function FetchUsers() {
const [users, setUsers] = useState([])
useEffect(() => {
const startFetching = async () => {
const response = await fetch('/users')
const fetchedUsers = await response.json()
users = fetchedUsers // ! users
users.push(...fetchedUsers) // ! users
setUsers(fetchedUsers) // !
}
startFetching()
}, [])
return (
<ul>
{users.map(user => <li>{user}</li>)}
</ul>
)
}
3. Atualizar o estado no componente de classe
As atualizações de estado assíncrono são comuns para componentes de classe.
Vamos considerar um exemplo:
import { Component } from 'react';
class DoubleIncreaser extends Component {
state = {
count: 0
};
render() {
return (
<>
<button onClick={this.doubleIncrease}>
Double Increase
</button>
<div>Count: {this.state.count}</div>
</>
);
}
doubleIncrease = () => {
// !
this.setState(({ count }) => ({
count: count + 1
}));
this.setState(({ count }) => ({
count: count + 1
}));
// !
// this.setState({ count: this.state.count + 1 });
// this.setState({ count: this.state.count + 1 });
}
}
Observe o manipulador doubleIncrease (): ele usa uma função de retorno de chamada para atualizar o estado.
Abra esta demonstração e clique no botão. O valor de this.state aumentará para 2.
Em componentes de classe, this.state também não é atualizado instantaneamente. Quando this.setState (newState) é chamado, o React adia a atualização de this.state até a próxima renderização.
Portanto, this.setState (newState) atualiza this.state de forma assíncrona.
4. Conclusão
O gancho useState () e this.setState () (dentro do componente de classe) atualizam o valor da variável e o estado do componente de forma assíncrona.
Lembre-se de uma regra simples: chamar o setter setState (newValue) do gancho useState () (ou this.setState ()) não atualiza o estado imediatamente, mas na próxima renderização do componente.
Você percebeu que o React agora só precisa ser importado uma vez (em index.js)? Isso não é mais necessário nos componentes.
Obrigado pela atenção e tenha um bom dia.