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>
}
"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>
}
Vamos rodar o projeto:
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 osetInterval
- Utilizando o
setTimeout
no lugar dosetInterval
(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>
}
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>
}
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:
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);
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()));
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()}`);
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];
}
Link Github SolidJs: SolidJS
Top comments (0)