useState — Aprofundando em React Hooks (2021)

Ricardo Pedroni
RPEDRONI
Published in
6 min readFeb 2, 2021

Bem-vindos à série sobre g̵a̵n̵c̵h̵o̵s̵ hooks em React! Em cada aula, abordaremos os hooks oferecidos pelo React, nos aprofundando em cada um, indo além do seu uso básico e entendendo uma vez por toda quais existem, porque existem, c̵o̵m̵o̵ ̵a̵c̵a̵b̵a̵r̵ ̵c̵o̵m̵ ̵o̵ ̵h̵á̵b̵i̵t̵o̵ ̵d̵e̵ ̵f̵i̵c̵a̵r̵ ̵p̵e̵n̵s̵a̵n̵d̵o̵ ̵e̵m̵ ̵p̵i̵r̵a̵t̵a̵s̵ e como usar efetivamente cada um deles!

🎥 Veja essa aula no YouTube também!

Fato pouco conhecido: Jack Sparrow foi grande precursor do uso de ganchos e machine learning.

Nessa primeira aula, abordaremos o mais clássico, o mais básico (e quiçá, o mais útil) dos hooks, o useState.

Mantenha Seu Estado

Desde que o React existe, existe a noção de que uma aplicação precisa de alguma forma de manipular estado, ou seja, ter alguma forma de memória, capaz de lembrar de um valor para seu uso futuro. Para quem usou o React em versões mais antigas, isso se dava através do famigerado this.setState

Na época, quando estávamos trabalhando com class, ninguém dava muita bola como o estado era mantido porque manter estado dentro de uma classe (seja um valor estático ou numa instância) é algo trivial para qualquer um que já trabalhou com programação orientada a objetos. Usamos this.state e this.setState sem pensar muito e achamos por um bom tempo que tudo era feliz e estava bem no reino do React...

Ilustrado aqui, uma moça bem com o reino do React (provavelmente parou de usar Angular também)

…MAS, quando React decidiu fugir de classes (e por bom motivo) e descomplicar a API do React para algo mais simples como funções, tudo mudou.

A decisão do React suportar componentes funcionais — isto é, componentes que são na verdade… funções — foi excelente por várias razões, especialmente pela maior simplicidade da criação e teste dos componentes. Mas com isso, apareceu uma dificuldade que para quem meramente usa React talvez não tenha pensado — como que podemos manter estado em algo inerentemente sem estado?

Para demonstrar isso, vamos montar o mesmo componente de antes, agora usando components funcionais

Maravilha! Transformamos nosso componente feio de classe num componente funcional muito mais simples, que faz apenas o que esperamos que ele faça. Vamos agora rodar nosso lindo componente e ver a mágica acontecer…

…Ué? Se a gente rodar um app com esse componente, você vai notar que nada acontece. Podemos apertar o botão mil vezes e ele continua mostrando 0. Que que pode ser o problema?

AHA, já sei! Toda vez que a função "roda", ele seta o valor de count para zero, é isso! Vamos então colocar a variável count fora da função, para que ele não resete o valor toda vez que o componente for renderizar:

Agora sim! Vamos lá, apertar nosso botão mágico…

….e nada de novo. Que raios tá acontecendo aqui? Bem, pelo menos temos nosso console amigo ali para no mínimo dizer qual o valor de count toda vez:

Ué, mas se o valor de counttá subindo afinal de contas…

…por que que nosso componente não atualiza?

Uma coisa importante de lembrarmos da versão clássica do React (usando classes) é que NUNCA deveríamos atualizar o estado diretamente na variável de estado this.state — ou seja, nunca faça algo como this.state.count = 10(sua IDE provavelmente te daria uma mensagem de erro, algo como “Não atualize o estado diretamente”). A razão disso não é que o valor count não seria atualizado mas que o React seria incapaz de saber que era necessário atualizar (i.e. fazer o rerender) o componente. Recorde que o React, além de tudo, faz a otimização do render da nossa aplicação, apenas pintando/atualizando o "lado visual" (DOM, Views no mobile, etc.) quando necessário, usando um algoritmo interno bem inteligente para isso. Quando usamos this.setState({ count: count + 1 }), não apenas atualizamos o valor de count mas indicamos ao React que queremos potencialmente atualizar a tela com novos dados.

Discutimos isso tudo para chegar na nossa conclusão: quando falamos de salvar estado em React, na verdade estamos falando que precisamos de uma forma de salvar estado + sinalizar que queremos atualizar o componente.

E para componentes funcionais e o futuro do React, a forma de fazer isso é através de hooks — nesse caso, o useState.

Bora ver como essa criança funciona:

“Vetores Descontruídos” podem ser também chamados de “Vetores Lacração”

useState devolve o valor que queremos manter em estado e uma função de atualização (geralmente chamada genericamente de setState), capaz de salvar e atualizar esse valor. Da mesma maneira que nunca devíamos usar o this.state.count = 5, nunca devemos atualizar o valor devolvido diretamente (no exemplo, NÃO podemos fazer count = 5, até porque count é uma constante).

Através da função setXXX devolvida (o nome é irrelevante mas é boa prática chamar essa função de set seguido do nome que você deu à variável) é possível atualizar o valor e notificar ao React que desejamos fazer uma atualização visual do componente. Para modernizar nosso componente de classe de antes, vamos agora usar hooks e adicionar mais uns elementos (exemplo retirado da documentação do React):

Reparou que passamos o valor ao useState? Esse é o valor inicial da variável e pode receber qualquer coisa, inclusive uma prop do componente, como fizemos com o initialCount.

A função de atualização setXXX(no nosso exemplo, setCount) pode receber um valor qualquer também. Caso quisermos atualizar a variável, se baseando no valor atual da própria variável, é possível passar uma função ao setCount e essa função receberá como parâmetro esse valor atual.

Uma coisa interessante é que o React também é inteligente para saber se um rerender deve ser feito ou não — caso você está querendo atualizar o estado com o mesmo valor prévio dele, por exemplo, setando o count para 0 se ele já é 0, o React não vai fazer um outro render porque não tem nada para atualizar, já que o valor é o mesmo.

Para quem veio do mundo de componentes de classe antigos do React, uma coisa para se atentar é que o useState não fazer um merge de objetos como o this.setState fazia:

Mesmo chamando o setState com apenas o count no objeto, o React sabia que você não queria sobrescrever todo o estado com isso, e fazia o merge desse objeto passado com o que ele já tinha dentro de this.state. Já no caso do useState, o valor que você passar para a função de atualização do valor vai ser o valor que ele vai salvar, sobrescrevendo qualquer coisa que havia lá previamente, podendo gerar alguma confusão para quem ainda usa os componentes de classe.

Nesse exemplo, repare que X: 10 vai aparecer inicialmente no seu componente mas, a partir da primeira clicada no botão de incrementar, por mais que count atualize corretamente, o valor de x simplesmente vai sumir porque o que foi salvo em state foi sobrescrito pelo objeto { count: state.count + 1 }.

Por causa disso, é prática comum não salvar tudo num grande objeto de estado, mas sim usar múltiplos useState para cada valor de informação relacionada que deseja ter em estado

Uma conclusão que você pode ter chego depois de ver isso é que o useState não é uma solução muito boa para estruturas ou objetos grandes e possivelmente complexos (estrelinha para você ⭐). No entanto, existem inúmeras bibliotecas e mesmo outros hooks fornecidos pelo React (como o useReducer que discutiremos numa aula futura) que podem fazer isso de forma muito mais estruturada, com o custo de tornarem seu código um pouco mais difícil de escrever e ler ~ mas falaremos disso quando essa aula chegar, aguarde ✨

Fechamos aqui a Parte 1 dessa aula! Na próxima parte, vamos ver como o React trata do useState internamente, quais garantias ele te dá (o React é um menino?) e quais são as otimizações que podemos fazer para garantir que seus componentes e suas aplicações rodem suaves.

Aqui é o Professor Ricardo saindo, fique na paz e até a próxima! ✌️

--

--

Ricardo Pedroni
RPEDRONI

O Professor Ricardo Pedroni ensina conceitos importantes e boas práticas de desenvolvimento de projetos em software. YouTube https://bit.ly/3q0TIAU