Executando verificação de segurança...
4

A biblioteca que transforma o React.js no Solid.js

O Problema

Uma das maiores críticas ao React é que ironicamente apesar do nome, a ferramenta não é realmente reativa e a forma que ela usa para simular uma reatividade é re-executar todo o componente toda vez que um estado ou prop é alterado
Isso infelizmente acaba levando a muitos outros problemas como por exemplo:

  • Os rules of hooks que limitam como e onde um hook deve ser usado para que ele sempre seja invocado de forma consistente durante os renders
  • A necessidade de se usar context para distribuir estados de forma eficiente entre multiplos componentes mas sujeitando todos os componentes que invocam o contexto a novos renders toda vez que qualquer estado que está sendo distribuído pelo contexto é modificado
  • A necessidade de se usar o HOC memo() para evitar que um filho sofra um re-render junto com o pai
  • A recomendação de não se modificar estados dentro do useEffect já que este é um hook feito para ser usado fora do ciclo de render
  • A recomendação de não se ler ou modificar refs durante o ciclo de render já que elas não são limitadas pela imutabilidade dos renders e por não desencadearem novos renders quando modificados
  • A necessidade de se usar useMemo e useCallback para memoização de valores e funções com alto custo para serem gerados em todo render
  • Etc...

É claro que o próprio framework possui ferramentas internas para evitar renders desnecessários, como por exemplo:

  • Comparação de v-dom para checar se a mudança de estado resultou em alguma mudança visual no DOM
  • Comparação de referência de estados e props para determinar se houve uma mudança que exija um novo render

E até mesmo está sendo considerado uma etapa de compilação durante o build para auto memoização assim como o Vue já faz

Mas conforme os apps vão ficando mais e mais complexos mesmo todas essas soluções não são o suficiente e o framework vai se tornando um gargalo na performance do app

Os competidores

Para solucionar esse problema ao longo do tempo foram surgindo competidores como Solid.js e Svelte.js (na minha opinião o melhor framework javascript de todos) que usam uma etapa durante o build para analizar o código e compilar uma versão em vanilla javascript em que somente as partes especificas que necessitam de reatividade reagiriam a uma mudança de estado.
O que acaba gerando apps que:

  • Não precisam de V-DOM e conseguem manipular o DOM diretamente com muito mais performance
  • Não precisam enviar um runtime especial para o cliente, sendo assim muito menores e mais rápidos
  • Tem soluções muito mais eficientes para gerenciamento de estado tanto local quanto global

As soluções da comunidade

Para tentar solucionar o problema de gerenciamento de estado e reatividade dentro do react foram também surgindo ao longo do tempo diversas bibliotecas de terceiros como por exemplo:

  • Redux
  • MobX
  • Recoil
  • Akita

Estes são alguns dos que se tornaram muito populares mas que já não recomendo em comparação a por exemplo:

  • React-Query
  • X-State
  • Jotai
  • Valtio
  • Zustand

Mas o que praticamente todos tem em comum é a necessidade de algum tipo de seletor para evitar renders desnecessários e forçar renders quando necessário
Até que no ano passado surgiu uma solução que prometia acabar com a dependencia de renders para reatividade

Signals

Signals é o nome da biblioteca mas também é o nome do método utilizado (o mesmo que o Solid.js utiliza), que consiste em criar um ponto alto gerenciado e que se alto atualiza quando há uma mudança

A biblioteca foi criada pela mesma equipe por trás do Preact.js que é uma alternativa leve e performática ao React mantendo as mesmas APIs

Ao criar um estado usando a função signal() da biblioteca você recebe de volta um signal, um objeto com estabilidade referencial (o que exclui a necessidade de se usar o HOC memo e os renders do context) e com a propriedade value e o método peek

A propriedade .value é onde o valor do signal fica guardado e onde você deve modificar-lo, as mudanças no valor do signal não irão forçar novos renders no componente desde que o value não seja invocado durante o render

O método .peek() permite ler o valor do signal mesmo durante o render sem forçar novos renders quando o valor do signal é modificado

Além disso o signal pode ser utilizado diretamente no corpo do retorno JSX e em input bindings para atualizar a UI sem a necessidade de novos renders

A biblioteca também disponibiliza a função computed() que permite criar signals reativos a outros signals e estados, a função effect() que permite criar lógica reativa sem depender de renders ou useEffect e batch() que permite fazer atualizações de valores em fornada

Os signals podem ser criados tanto de dentro quanto de fora de componentes ou de hooks o que permite o compartilhamento de estado apenas exportando o signal em um arquivo e importando onde necessário, mas signal e computed possuem as versões hooks useSignal e useHook para serem usados para criar signals dentro de componentes e hooks

Exemplo

No exemplo a seguir eu criei um app com 2 instancias do mesmo componente counter, um recebendo o valor a partir de um signal e o outro a partir de um useState

Quando qualquer um dos contadores passa de 10 o valor é resetado para 0

Utilizando a extensão do react para chrome podemos ver um highlight ao redor do componente toda vez que ele sofre um novo render
(Abra a imagem em uma nova guia para ver o gif)

https://sat02pap003files.storage.live.com/y4mJM7y4xxNiMTqUh_N8ZZvN1M2_oylmR5D15fAOVaQqo3kg76eUA4zgwJzpJ967HULF8GK_ZT66wJ3Xr-r-uOwwKhyGWBf4D-QLGG9TjnBYqG-Wkam51r22i3AJIOzemTCNvC2bpFpqqF9uBK6n_GgMM_vpHP6spT1y4Nj1N465H36zUYbRVif5WjGPt2H9mbt?width=756&height=657&cropmode=none

Mas perceba que enquanto o counter feito com useState força renders em todo o app toda vez que é atualizado o counter feito com signals não gera nenhum re-render, seja com a mudança de estado no evento ou no effect

Mais do que isso, o quando o counter com useEffect é resetado é forçado 2 re-renders, pois como o useEffect é executado fora do ciclo de render ele precisa forçar um novo render para atualizar o valor

Profiler do counter com Signal durante reset

Profiler do counter com useState

Conclusão

Signals é uma biblioteca revolucionária que permite criar apps complexos e performáticos com facilidade sem a necessidade da maior parte dos hooks do prórprio react

Carregando publicação patrocinada...
1