Exemplos de Vanilla JSX
E se JSX retornasse elementos DOM?
- A função
ClickMe cria um botão e exibe a contagem de cliques
- O texto é atualizado cada vez que o botão é clicado
export default function ClickMe() {
let i = 0;
const el = Click me as HTMLButtonElement;
el.onclick = (e) => {
el.textContent = `Clicked ${++i} times`;
};
return el;
}
Reutilização
- O componente
ClickMe pode ser usado várias vezes, mantendo estados diferentes para cada instância
import ClickMe from "./sample1.js";
export default () =>
;
Criação de uma árvore DOM interativa
- É possível gerenciar uma lista de tarefas usando as classes
TodoInput e TodoList
- Itens podem ser adicionados e removidos ao clicar neles
function TodoInput(attrs: { add: (v: string) => void }) {
const input = as HTMLInputElement;
input.placeholder = 'Add todo item...';
input.onkeydown = (e) => {
if (e.key === 'Enter') {
attrs.add(input.value);
input.value = '';
}
};
return input;
}
class TodoList {
ul = as HTMLUListElement;
add(v: string) {
const item =
- {v}
as HTMLLIElement;
item.onclick = () => item.remove();
this.ul.append(item);
}
}
export default () => {
const list = new TodoList();
list.add('foo');
list.add('bar');
return
list.add(v)} />
{list.ul}
;
};
Processamento de grandes volumes de dados
- A função
FindNames processa e filtra grandes volumes de dados para exibir os resultados
- Os itens correspondentes são atualizados em tempo real conforme o valor de entrada
import { data } from "../fetch-dataset.js";
export default function FindNames() {
const status = as HTMLParagraphElement;
const results = as HTMLUListElement;
const input = as HTMLInputElement;
updateMatches();
function updateMatches() {
const matched = (data.entries().filter(([k]) => k.match(input.value)).toArray());
const matches = (Iterator.from(matched).map(match => ).take(30));
results.replaceChildren(...matches);
status.textContent = `${matched.length} / ${data.size}`;
}
return
{input}
{status}
{results}
;
}
function Item(attrs: { match: [string, number], regex: string }) {
const [name, count] = attrs.match;
const total = ({count});
return
-
{total}
;
}
function highlight(str: string, regex: string) {
if (!regex) return str;
const r = new RegExp(`(${regex})`, 'gi');
return str.replace(r, '$1');
}
Introdução ao imlib
imlib é uma biblioteca desenvolvida para o immaculatalibrary.com
- Ela é usada para construir o minigamemaker.com e o site que você está lendo agora
- Foi desenvolvida porque o estado da arte existente não era suficiente, e é a forma preferida de criar apps
Resumo do GN⁺
- Este artigo explica como criar e interagir diretamente com elementos DOM usando JSX
- Ele apresenta uma forma de processar grandes volumes de dados com eficiência sem usar um virtual DOM
- A biblioteca
imlib permite desenvolver apps de maneira simples e intuitiva
- Outros projetos com funcionalidades semelhantes incluem React e Vue.js
1 comentários
Opiniões no Hacker News
Retornar nós DOM reais praticamente neutraliza grandes vantagens do JSX e de bibliotecas não JSX como Lit: APIs em estilo modo imediato e o modelo
UI=f(state)É preciso retornar uma descrição do DOM, não o DOM real, para reavaliar o template com o novo estado e atualizar com eficiência o DOM em que esse template é renderizado
Os exemplos atualizam usando APIs imperativas do DOM, como
input.onkeydown = ...outhis.ul.append(item), mas evitar esse tipo de código e percorrer os itens no template provavelmente é o principal benefício do DOM virtualDito isso, o problema do DOM virtual é que o cálculo de diferenças é lento, e isso pode ser resolvido com templates que separam partes estáticas e dinâmicas, como no Lit
Pelo contrário, ele leva a pensar “posso renderizar de novo uma UI grande à vontade que o DOM virtual dá conta”, o que acaba tendo efeito contrário: o desempenho real fica ruim, mas a estrutura do app já se cristalizou de um jeito difícil de corrigir sem reescrever
Vi o mesmo padrão em quatro equipes e, como arquiteto, recomendei uma estrutura vanilla consciente de desempenho com base nos problemas que teríamos com React, mas isso não foi aceito sob o argumento de que “há muitas maneiras de evitar”
No fim, parece que em muitos casos é preciso aprender sofrendo na prática
createElement, e os benefícios descritos vêm do framework e do runtimeEm termos mais curtos, JSX é uma sintaxe alternativa de chamada de função com usos úteis
Em uma empresa anterior, usávamos JSX para fábricas de dados de teste; ele parecia XML, mas na etapa de criação dos elementos era possível tomar decisões contextuais ajustadas aos dados finais usando o padrão builder
Não tinha relação com React ou DOM, nem significava que aquilo não pudesse ser expresso declarativamente sem JSX
Pessoalmente, prefiro atualizar o DOM de forma imperativa. Dá para controlar com muita precisão o que acontece e projetar uma estrutura muito eficiente
Também fica mais fácil adicionar, alterar, remover e corrigir funcionalidades do app sem precisar moldar o raciocínio à metodologia rígida de outra pessoa
UI=f(state), que são pontos fortes do JSX e de bibliotecas não JSX como Lit, mas isso parece uma das abstrações com vazamento mais marcantes de toda a computaçãoHá um motivo para ter surgido todo um ecossistema em torno do React sobre como evitar múltiplas renderizações e impedir atualizações desnecessárias
Criei este projeto por frustração com o estado dos geradores de sites estáticos nos últimos 10 anos
Como faço principalmente sites estáticos, queria uma ferramenta simples e intuitiva, e JSX parecia se encaixar bem, mas eu estava cansado da complexidade excessiva de frameworks JSX como React
Então criei um gerador de sites estáticos que renderiza JSX como strings, e estendê-lo para o lado do navegador, fazendo JSX renderizar como elementos DOM, foi um passo natural
Em alguns casos, especialmente em layouts, ele também funciona bem para componentes compartilhados. No geral, estou satisfeito com o resultado, embora algumas partes sejam bem hacky e o suporte das IDEs ainda possa melhorar
Além disso, essa abordagem também se encaixa bem com SEO. Era um problema que eu não sentia que tivesse sido resolvido adequadamente em outros frameworks JSX
Na documentação, talvez seja melhor escrever “static site generator” por extenso em vez de “SSG”. Eu já usei geradores de sites estáticos, mas não sabia o que era SSG e tive que perguntar a uma IA
Vim do Vue e me surpreendi: o lit-html faz muitas coisas que os templates do Vue fazem, incluindo ligar eventos, usando apenas templates em JS vanilla simples
Com a extensão lit do VSCode, dá para ter destaque de sintaxe e verificação completa de tipos até dentro dos templates
Descobri isso depois que Marc Grabanski tweetou que usa lit-html com vanillajs, e não Lit; ao experimentar por conta própria, funcionou muito bem. Parece bastante parecido com o que você está tentando resolver agora
Usando o pacote de templates
lit-html, dá para fazer a maior parte do que é descrito no capítulo de templates: https://lit.dev/docs/templates/overview/Também é possível sem a abstração de componentes do
lit-element: https://lit.dev/docs/libraries/standalone-templates/#renderi...O motivo pelo qual esses “e se” são interessantes é que a origem do JSX pode ser rastreada até o XHP do Facebook, e o XHP foi explicitamente inspirado no E4X, um padrão JS inicial que se parecia e se comportava de forma semelhante à biblioteca descrita aqui
[1] https://engineering.fb.com/2010/02/09/developer-tools/xhp-a-...
[2] https://en.m.wikipedia.org/wiki/ECMAScript_for_XML
Esse também foi o motivo pelo qual o JSX foi além do E4X, e depois disso não houve nenhuma proposta séria para templates HTML dentro do JS
Ainda assim, parece possível reviver a ideia geral com um acabamento moderno: https://github.com/WICG/webcomponents/issues/1069
for(of)em vez defor eachO motivo de não termos ganhado
for (:)é ainda mais absurdo: era porque poderia conflitar com anotações:typeque alguns membros do TC39 acreditavam que um dia entrariam magicamente na linguagemJá criei uma biblioteca de UI com a ideia de que expressões de template JSX criassem nós reais do DOM
Ela também eliminava parte do boilerplate de handlers de eventos imperativos ao vincular objetos de modelo a atributos. Como é de se imaginar, acho que é uma boa ideia
https://github.com/tomtheisen/mutraction
Dava para escrever código que cria um modelo com
track({ clicks: 0 }), incrementamodel.clicksao clicar e reflete esse valor diretamente no DOMAqui também vale mencionar o VanJS: https://vanjs.org/
Outras bibliotecas JSX, como Solid.JS, também retornam nós do DOM, e é bom ver essa ideia ganhando força
Acho que quanto mais perto ficarmos da plataforma que usamos, melhor. Camadas de abstração podem ser úteis às vezes, mas na prática ainda não encontrei uma necessidade real de esconder a plataforma
Projetos enormes como os do Facebook talvez se beneficiem disso, mas nunca trabalhei nessa escala
Os exemplos são legais, mas parece importante que eles não mostrem props de componentes que possam mudar ao longo do tempo
Essa capacidade em si não parece estar modelada. Se você não precisa disso, é uma abordagem inteligente, mas não consigo ver bem como isso escala para apps mais complexos
A diferença é apenas escrever de forma mais concisa as 10 linhas de código que normalmente criariam e configurariam elementos do DOM
Na verdade, a parte realmente interessante desse framework é quase todo o resto. Há o lado do gerador de sites estáticos retornando JSX como strings, a importação de diretórios de código-fonte bruto para manipular
string|Bufferno momento do SSG, um sistema de módulos próprio, extremamente eficiente e rápido, construído sobrechokidareswc, etc.Usar JSX como DOM é a parte visualmente mais chamativa, mas na prática é quase um truque de festa
Por exemplo, o código-fonte do vanillajsx.com é muito conciso, claro e curto. Escrevi tudo hoje, sem dependências além de
imlib, e a demo de JSX-as-DOM é a parte menos inovadora: https://github.com/sdegutis/vanillajsx.com/tree/main/siteSe você gosta dessa abordagem em que JSX retorna elementos concretos do DOM, o Solid funciona exatamente assim, com uma camada de reatividade adequada adicionada por cima
setTimeoutousetIntervalDito isso, concordo que esses projetos muitas vezes funcionam bem em casos de uso pequenos, mas desmoronam rapidamente em cenários do “mundo real”
A implementação não parece ser tão difícil
Isto é muito parecido com Vanilla TSX: https://github.com/wisercoder/uibuilder
Um exemplo de app escrito com Vanilla TSX está aqui: https://github.com/wisercoder/eureka/tree/master/webapp/Clie...
Isso me lembra o ActionScript 3, que tinha XML no núcleo da linguagem
Era uma linguagem divertida de escrever, mas falhou de forma célebre em se tornar o ES4. No fim, levou mais de 10 anos para chegarmos a um ponto parecido com TypeScript e JSX
Foi desativado para páginas web no Firefox 17, seis meses antes do primeiro lançamento do React
Fiquei curioso se há mais alguém para quem o último exemplo não funciona no Firefox. Funcionou no Edge, mas falhou no Firefox
Uncaught (in promise) TypeError: Map.groupBy(...).entries().map is not a functionNão entendo bem por que JSX é mais atraente do que escrever algo assim:
h("div", {}, [ h("p", {}, "this is easy"), ...list.map((l) => h("li", {}, l)) ])Dessa forma, você ganha automaticamente loops, interpolação de variáveis etc. sem precisar criar um compilador e uma nova sintaxe. Gostaria que alguém explicasse
Para ser justo, no JSX você também usa loops comuns e interpolação do mesmo jeito.
{}aceita expressões de JS puroSó é necessária uma etapa de compilação para expandir as tags de elementos em chamadas a
createElementCada pessoa processa informações de um jeito, mas aquele exemplo tem tanta pontuação que é muito difícil entendê-lo rapidamente
A estrutura do DOM que será gerada não fica visível sem decompor mentalmente a sintaxe, e entender a estrutura do DOM de relance é muito mais importante do que precisar ou não de um compilador
Para contexto, sou uma pessoa neurodivergente, e espero que essa explicação ajude
Como é parecido com o que se vê nas ferramentas de desenvolvedor do navegador, fica mais fácil comparar e depurar
Mas, em apps complexos, quando os componentes chegam às centenas e começam a importar uns aos outros, a forma de escrever com tags JSX passa a parecer uma sintaxe simples e fácil de entender
A resistência ao React também vem muito do fato de ele ser exagerado para coisas simples — e de fato é
Mas as pessoas criam apps com complexidades e requisitos diferentes, então não dá para simplificar dizendo que um lado é mais atraente. São ferramentas diferentes para problemas diferentes