DEV Community

Cover image for SolidJs o novo React, porem melhor 😎
Tauan Tathiell
Tauan Tathiell

Posted on

SolidJs o novo React, porem melhor 😎

Introdução

Comecei a trabalhar profissionalmente com react a uns 4 anos, tive o prazer de ver essa library virar o que se tornou atualmente, antes tínhamos de criar smart components estendendo a class Component do react, depois tivemos a introdução dos hooks aonde ao invés de utilizar class components utilizamos function components com os hooks [useState, useEffect, useMemo, useContext, useReducer], isso fez com que a verbosidade do código desse uma leve diminuida.

"OK, mas esse post não é sobre SolidJs?"

Para falarmos sobre o solid-js temos que dar um contexto de como as coisas são feitas no react.

Aqui temos um exemplo utilizando os Hooks do react para um simples component de contador.

function Counter() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    setInterval(() => {
      setCount(count + 1)
    }, 1000)
  })

  return <div>Count: {count}</div>
}
Enter fullscreen mode Exit fullscreen mode

"Mas pera ai, esse useEffect fica me estourando um warning", sim, ele dirá que esta faltando uma dependência no Array dependency do useEffect, bora adicionar para parar com warning.

function Counter() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    setInterval(() => {
      setCount(count + 1)
    }, 1000)
  }, [count])

  return <div>Count: {count}</div>
}
Enter fullscreen mode Exit fullscreen mode

Vamos rodar o projeto:

Re-run glitch

Mas agora nos deparamos com outro problema, apos alguns anos trabalhando com react começamos a lutar contra esse problema diariamente, o famoso re-run, podemos solucionar esse problema de re-run no component Counter de algumas formas:

  • Retornando do useEffect uma function que limpa o setInterval
  • Utilizando o setTimeout no lugar do setInterval (uma ótima pratica porem seria necessário a abordagem a cima de limpar a função)
  • Usando a própria função para retornar o valor anterior diretamente como o valor atual

Vamos utilizar a última opção aqui:

function Counter() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    setInterval(() => {
      setCount(prevCount => prevCount + 1)
    }, 1000)
  }, [])

  return <div>Count: {count}</div>
}
Enter fullscreen mode Exit fullscreen mode

Chegamos a uma ideia de que o react tem uma "falsa reatividade" 🧐 .

Vamos falar um pouco sobre o SolidJS

Primeiro de tudo, solid-js nao esta tentando re-inventar a roda, solid-js é identico ao react, vamos criar nosso component Counter utilizando o solid-js.

function Counter() {
  const [count, setCount] = createSignal(0)

  setInterval(() => {
    setCount(count() + 1)
  }, 1000)

  console.log('the counter called!')

  return <div>Count: {count()}</div>
}
Enter fullscreen mode Exit fullscreen mode

Vemos aqui uma grande diferença, count no solid é uma função. no solid isso é chamado accessor e isso é uma das coisas misticas por tras de como o solid funciona. Okay observámos no react que temos que fazer uma limpeza do setInterval ou pegar o valor da própria função setCount para retornar o valor anterior como valor corrente, para poder funcionar sem o famoso re-render, certo?

Não, :D só esse código já funciona.

Adicionamos um console.log para verificar quantas vezes foi renderizado esse component durante a atualização do count, checaremos quantas vezes ele roda no console:

Image description

Magic!!!! No solid seu código não roda mais de uma vez a não ser que isso seja requerido em algum momento do código.

Mas como Solid funciona?

O gerenciamento de dados do Solid é construído a partir de um conjunto de primitivas reativas flexíveis que são responsáveis por todas as atualizações. Ele tem uma abordagem muito semelhante ao MobX ou Vue, exceto que nunca troca sua granularidade por um VDOM. Dependências são rastreadas automaticamente quando você acessa seus valores reativos em seus efeitos e código JSX View, os primitivos do Solid vêm na forma de chamadas create que geralmente retornam tuplas, onde geralmente o primeiro elemento é um primitivo legível e o segundo é um setter. É comum referir-se apenas à parte legível pelo nome primitivo.

Primitivos

O Solid é composto de 3 primitivas primárias: Signal, Memo e Effect. Em seu núcleo está o padrão Observer, onde Signals (e Memos) são rastreados envolvendo Memos e Effects.

Os Signals são os primitivos mais simples. Eles contêm valor e funções get e set para que possamos interceptar quando eles são lidos e escritos.

const [count, setCount] = createSignal(0);
Enter fullscreen mode Exit fullscreen mode

Effects são funções que envolvem leituras de nosso Signal e são executadas novamente sempre que o valor de um Signal dependente muda. Isso é útil para criar efeitos colaterais, como renderização.

createEffect(() => console.log("The latest count is", count()));
Enter fullscreen mode Exit fullscreen mode

Finalmente, Memos são valores derivados armazenados em cache. Eles compartilham as propriedades de Signals e Effects. Eles rastreiam seus próprios Signals dependentes, reexecutando apenas quando eles mudam, e eles próprios são Signals rastreáveis.

const fullName = createMemo(() => `${firstName()} ${lastName()}`);
Enter fullscreen mode Exit fullscreen mode

Como esse Signal funciona?

Signals são emissores de eventos que contêm uma lista de assinaturas. Eles notificam seus assinantes sempre que seu valor muda.

As coisas ficam mais interessantes como essas assinaturas acontecem. Solid usa rastreamento automático de dependência. As atualizações acontecem automaticamente conforme os dados mudam.

O truque é uma pilha global em tempo de execução. Antes que um Effect ou Memo execute (ou reexecute) sua função fornecida pelo desenvolvedor, ele empurra a si mesmo para aquela pilha. Então, qualquer Signal que é lido verifica se há um ouvinte atual na pilha e, se houver, adiciona o ouvinte às suas assinaturas.

Você pode pensar assim:

function createSignal(value) {
  const subscribers = new Set();

  const read = () => {
    const listener = getCurrentListener();
    if (listener) subscribers.add(listener);
    return value;
  };

  const write = (nextValue) => {
    value = nextValue;
    for (const sub of subscribers) sub.run();
  };

  return [read, write];
}
Enter fullscreen mode Exit fullscreen mode

Link Github SolidJs: SolidJS

Top comments (0)