O gancho useState - Um guia completo

O gancho useState – Um guia completo

Nó Fonte: 1780723

O que é um estado?

Antes de nos aprofundarmos no gancho useState, vamos primeiro entender o termo Estado.

Estado representa informações sobre algo em um determinado momento.

Por exemplo, vamos considerar uma caixa de texto.

Inicialmente, não há nada dentro desta caixa de texto, então seu estado é vazio. Suponha que você comece a digitar Hello dentro dele, para cada pressionamento de tecla o estado da caixa de texto mudará. Inicialmente será “H”, depois “He”, depois “Hel” e assim sucessivamente até se tornar “Hello”.

Além disso, observe que enquanto você digita, você não está perdendo o valor anterior. Se você pressionar “H” seguido de “e” você obterá “He” e não apenas “e”. Em outras palavras, você pode pensar no estado como o memória da caixa de texto.

A necessidade de estado em um componente React.

Vamos entender isso com a ajuda de um exemplo.

Codesanbox sem estado

Aqui temos um Contador de cliques componente que exibe o número de vezes que o botão Incrementar foi clicado.

Estamos usando um variável local “contador” para manter a contagem dos cliques.

Cada vez que clicamos no botão Incrementar, manipularClique função será invocada. Esta função aumentará o valor do contador em 1 e também registrará o valor no console.

Vá em frente, clique no botão Incrementar na visualização do CodeSandbox.

Nada aconteceu?

Bem, nossa lógica parece estar correta. O valor registrado no console (CodeSandbox) é atualizado corretamente toda vez que clicamos, mas por que essa atualização não é refletida na interface do usuário?

É por causa da maneira como o React funciona.

  • As alterações nas variáveis ​​locais não acionam uma nova renderização.
  • Durante uma nova renderização, um componente é criado do zero, ou seja, a função de um componente (neste exemplo é a função ClickCounter) é executada novamente. Como as variáveis ​​(por exemplo, contador) são locais para a função, seus valores anteriores são perdidos.

Então, como fazemos com que o componente lembre os valores entre as renderizações?

Gif chegando a uma resposta

Sim, você acertou! Fazemos isso com a ajuda do usarEstado gancho.

O gancho useState

O gancho useState fornece mecanismos para preservar o estado e acionar uma nova renderização.

Vejamos seu uso.

import React, { useState } from "react";
const state = useState(initialValue); // OR const state = React.useState(initialValue);

O gancho useState retorna um array que contém dois itens:

  • A Estado variável que retém seus valores durante as re-renderizações. O valor inicial passado para useState é atribuído à variável de estado durante a primeira renderização.
  • A função setter que atualiza a variável de estado e também aciona uma nova renderização.
const state = useState(0);
const data = state[0];
const setData = state[1];

utilização desestruturação de array , podemos refatorar as instruções acima em uma única instrução, conforme mostrado abaixo:

const [data, setData] = useState(0);

O valor inicial passado para useState é usado apenas durante a primeira renderização. Para re-renderizações, ele é ignorado.

Contador com useState

Agora, vamos atualizar o exemplo de contador anterior para incluir o gancho useState.

  • Como precisamos do valor do contador entre as re-renderizações, vamos convertê-lo em um estado.
const [counter, setCounter] = useState(0);
  • Chamando setCounter dentro da função handleClick.
const handleClick = () => { setCounter(counter + 1); console.log(`%c Counter:${counter}`, "color:green");
};

A função setCounter atualizará o valor do contador em 1 e acionará uma nova renderização. Quando a função do componente é chamada em uma nova renderização, a variável de estado retornada por useState terá o valor atualizado.

Experimente o CodeSandbox com o código atualizado. Clique no botão Incrementar e veja a mágica do useState em ação.

Codesanbox com useState

Você pode verificar que em uma nova renderização, o componente funcional Contador de cliques é chamado novamente visualizando os logs do console. O log “ClickCounter start” que é adicionado no início do componente será registrado em cada renderização.

primeiro render

renderizar novamente

Função de atualização

Suponha que queremos aumentar o valor do contador em 4 em cada clique.

const handleClick = () => { setCounter(counter + 1); setCounter(counter + 1); setCounter(counter + 1); setCounter(counter + 1); console.log(`%c Counter:${counter}`, "color:green"); };

Suponha que o valor inicial de counter seja 0. O que você espera ver quando o botão for clicado?

Sem função de atualizador

Você esperava que a contagem fosse 4, certo? Mas por que você vê 1 em vez disso?

a) Cada renderização está associada a um estado. O valor desse estado permanece bloqueado durante o tempo de vida dessa renderização.

Observe que o log dentro da função handleClick imprime o valor do contador como 0.

Não importa quantas vezes você chame o método setCounter, o valor de counter permanece o mesmo.

const handleClick = () => { setCounter(counter + 1); setCounter(counter + 1); setCounter(counter + 1); setCounter(counter + 1); console.log(`%c Counter:${counter}`, "color:green"); };
b) Até que todo o código dentro de um manipulador de eventos seja executado, o React não acionará uma nova renderização.

Por esse motivo, cada chamada setCounter não aciona uma renderização individual. Em vez disso, o React adiciona essas funções setter em uma fila. Executa-os na ordem em que foram enfileirados. As atualizações feitas no estado após a execução de todas as instruções são refletidas na próxima renderização. Esse enfileiramento de várias atualizações de estado é conhecido como lotes. Ele permite que o React tenha mais desempenho.

Portanto, aqui temos uma única renderização em vez de 4 renderizações diferentes.

Este exemplo é simples e você pode corrigir esse problema atualizando o código conforme mostrado abaixo:

const handleClick = () => {
setCounter(counter + 4); console.log(`%c Counter:${counter}`, "color:green"); };

Mas e se você tivesse um caso de uso em que desejasse atualizar o estado várias vezes antes da próxima renderização.

É aí que o _ atualizador _ função vem a calhar.

Podemos refatorar o exemplo anterior com a função de atualização da seguinte forma:

const handleClick = () => { setCounter(prevCounter => prevCounter + 1); setCounter(prevCounter => prevCounter + 1); setCounter(prevCounter => prevCounter + 1); setCounter(prevCounter => prevCounter + 1); console.log(`%c Counter:${counter}`, "color:green"); };

Aqui prevContador ⇒ prevContador + 1 representa a função do atualizador.

Conforme explicado anteriormente, essas instruções do atualizador também são enfileiradas (em lote).

A função de atualização recebe um estado pendente/anterior que usa para calcular o próximo estado.

Função de atualização em lote

Abaixo está o CodeSandbox com a função de atualização adicionada. Tente clicar no botão de incremento.

Caixa de areia da função do atualizador

Função inicializador

Dê uma olhada no exemplo abaixo. Aqui estamos chamando a função getItems para obter o valor inicial do estado.

import React from "react";
import { useState } from "react";
function ListItems() { const getItems = () => { console.log(`%c getItems called`, "color:hotpink"); return Array(50).fill(0); }; const [items, setItems] = useState(getItems()); return ( <div className="card"> <ul> {items.map((item, index) => ( <li key={index}>Item {index + 1} </li>))} </ul> <button onClick={() => setItems([...items, 0])}>Add Item</button> </div> );
} export default ListItems;

Esta função cria um array com tamanho 50 e preenche o array com zeros. Consulte a imagem abaixo.

Matriz preenchida com 50 zeros

Esses itens são então exibidos na tela.

Tudo parece estar bem, mas temos um problema aqui.

Clique no Adicionar Item botão (localizado após a lista de itens) para adicionar um novo item à lista. Observe os registros.

Sem função inicializador

Você vê o problema aqui?

O log “getItems called” é adicionado ao console toda vez que você adiciona um item. Isso significa que esta função está sendo chamada em cada renderização.

Lembre-se que useState ignora o valor inicial passado para ele após a primeira renderização, mas aqui o valor inicial ainda está sendo recalculado. Isso pode ser caro se estivermos criando grandes arrays ou realizando cálculos pesados.

Podemos resolver este problema passando getItems como um _ inicializador _ função.

Agora, vamos fazer uma pequena alteração no código.

const [items, setItems] = useState(getItems);

Com função inicializador

Veja a janela do console no CodeSandbox. Observe que o log “getItems called” é impresso apenas na primeira renderização. Quando os itens subsequentes são adicionados, esse log não está lá.

Embora não haja uma diferença visual entre os dois exemplos, em termos de desempenho eles são diferentes.

Lembre-se quando precisar de uma função para o estado inicial, sempre passe a função ou chame a função dentro de outra função. Nunca chame a função diretamente.

✅ const [items, setItems] = useState(getItems);
✅ const [items, setItems] = useState(() => getItems());
❌ const [items, setItems] = useState(getItems());

Quantos ganchos useState posso ter

Você pode ter quantos ganchos useState dentro de um componente forem necessários.

Veja o CodeSandbox

Vários ganchos useState

O componente abaixo tem três estados diferentes – nome de usuário, senha, keepMeSignedIn.

Tente atualizar os valores de username, keepMeSignedIn. Os estados atualizados são registrados no console quando o botão de login é clicado.

Destaques

  • useState fornece um mecanismo para acionar uma nova renderização e persistir o estado entre as novas renderizações.
  • Use a função de atualizador quando precisar:
    • Calcule o próximo estado com base no estado anterior.
    • Execute várias atualizações no estado antes da próxima renderização.
  • Se o estado inicial for obtido de uma função – use a sintaxe da função inicializadora.
  • Pode haver vários ganchos useState dentro de um componente.

Gostou desta postagem? Compartilhe com outras pessoas.
Originalmente escrito para o meu blog pessoal – https://gauravsen.com/use-state-hook

Carimbo de hora:

Mais de Codementor React Fato