Cookie Consent by Free Privacy Policy Generator 📌 Web Components com Preact


✅ Web Components com Preact


💡 Newskategorie: Programmierung
🔗 Quelle: dev.to

O Preact se intitula como "Fast 3kB alternative to React with the same modern API". E na minha opinião, ele tá se subestimando. Não é minha intenção entrar em uma comparação de React vs Preact, mas a performance dele a possibilidade de criar web components são duas grandes vantagens. É esse segundo ponto que vamos abordar hoje.

Eu escolhi o Preact ao invés de outras libs como Lit ou Stencil porque além de ele ser muito leve e possuir uma ótima performance, os componentes são iguais aos do React, o que significa uma curva de aprendizado muito pequena caso o seu time já conheça React. Você consegue criar uma lib agnóstica sem abrir mão do TSX/JSX, hooks, e tudo aquilo que faz o React ser o que ele é, o que na minha opinião faz o Preact ser o melhor dos dois mundos no desenvolvimento de bibliotecas.

Por último, mas não menos importante, o Preact já oferece suporte nativo aos Signals, que te permite criar um gerenciamento de estado atômico e, mais uma vez, muito performático.

O projeto

O nosso objetivo vai ser bem simples, que é transformar um componente de counter em um web component. Sabe aquele counter que aparece quando você gera uma aplicação com o vite? Ele mesmo. Vamos usar uma técnica simples pra transformar esse cara em um web component que pode ser utilizado em qualquer lugar, inclusive em um HTML comum.

Mão na massa

Pra esse exemplo eu criei um projeto Preact no Stackblitz e vou alterá-lo para exportar e renderizar os web components. Se preferir, você também pode criar um projeto local usando o getting started.

Eu deletei o app.tsx e o app.css. Também removi o render() do main.tsx. Como nós vamos exportar o web component pra ser usado diretamente no HTML, não faz sentido renderizar o preact como aplicação.

Pra começar, crie um componente counter.tsx com o seguinte conteúdo:

import { FunctionalComponent } from 'preact';
import { useCallback, useState } from 'preact/hooks';

export const Counter: FunctionalComponent = () => {
  const [count, setCount] = useState(0);

  const increment = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return <button onClick={increment}>count is {count}</button>;
};

O pulo do gato

Qualquer componente preact pode ser registrado como web component usando o mini wrapper preact-custom-element. Esse cara transforma o componente em Web Component seguindo a V1 da especificação Custom Elements.

Pra instalar o wrapper, rode o seguinte comando:

npm install preact-custom-element

E se você está usando typescript, instale os types também:

npm i @types/preact-custom-element --save-dev

Agora, é só usar o wrapper no componente e o código do seu counter deve ficar assim:

import { FunctionalComponent } from 'preact';
import { useCallback, useState } from 'preact/hooks';
import register from 'preact-custom-element';

export const Counter: FunctionalComponent = () => {...};

register(Counter, 'ric-counter');

Por último, exporte o componente no main.tsx. Como removemos a maior parte desse arquivo, ele deve ficar assim:

import './index.css';

export * from './counter';

A partir daí você já consegue utilizar o seu web component no index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Preact + TS + Web Components</title>
  </head>
  <body>
    <ric-counter></ric-counter>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

Com isso, o web component será renderizado normalmente:

Botão counter sendo renderizado como web component

Você deve ter notado que eu declarei a tag <ric-counter></ric-counter> antes do import do main.tsx. Isso é pra mostrar que ele consegue detectar tags que já foram declaradas antes de ele ser inicializado, o que significa que você não precisa se preocupar em carregar o js antes das tags.

Atributos

Os atributos são essenciais pra permitir que a aplicação possa controlar o comportamento dos componentes, ao mesmo tempo que nós como desenvolvedores de componentes definimos o que pode ser controlado.

Os web components recebem os atributos como string por padrão, então é importante ter em mente que os seus dados podem precisar ser convertidos antes da utilização. Eu considero uma boa prática fazer isso já nas primeiras linhas do componente, e trabalhar internamente com a variável no tipo que eu quiser pra sempre converter tudo em um lugar único:

import { useCallback, useState } from 'preact/hooks';
import register from 'preact-custom-element';
import { FunctionalComponent } from 'preact';

interface CounterProps {
  label?: string;
  steps?: string;
}

export const Counter: FunctionalComponent<CounterProps> = ({
  label = 'Count is',
  steps: rawSteps = '1',
}) => {
  // Converto o atributo steps (rawSteps) pra number e uso como steps internamente
  const steps = Number(rawSteps);
  const [count, setCount] = useState(0);

  const increment = useCallback(() => {
    setCount(count + steps);
  }, [count]);

  return (
    <button onClick={increment}>
      {label} {count}
    </button>
  );
};

register(Counter, 'ric-counter', ['label', 'steps'], { shadow: false });
//          ^            ^           ^                       ^
//          |         tag HTML       |                   shadow-dom
//     Componente           Atributos observados

Sempre que um atributo observado for alterado, o componente vai ser atualizado. Os atributos que não estiverem nessa lista só serão detectados caso sejam passados na inicialização.

Já o shadow, é um booleano que indica se o seu componente deve usar ou não o Shadow DOM.

O HTML com os atributos:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Preact + TS + Web Components</title>
  </head>
  <body>
    <ric-counter label="Custom count:" steps="2"></ric-counter>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

Agora é só testar e ver um novo label e incrementando de dois em dois:

Botão counter customizado

Callbacks

Os callbacks são um tipo importante de atributo, afinal as pessoas que vão utilizar o nosso componente precisam saber se um botão foi clicado e/ou se o estado do componente mudou.

Como os atributos de um web component são passados como strings, é preciso passar as funções de callback de uma forma diferente: via JavaScript.

E pra tornar isso possível vamos adicionar uma nova propriedade ao nosso componente chamada onChange e executar esse callback dentro a função de increment:

import { useCallback, useState } from 'preact/hooks';
import register from 'preact-custom-element';
import { FunctionalComponent } from 'preact';

interface CounterProps {
  label?: string;
  steps?: string;
  onChange?: (count: number) => void;
}

export const Counter: FunctionalComponent<CounterProps> = ({
  label = 'Count is',
  steps: rawSteps = '1',
  onChange,
}) => {
  const steps = Number(rawSteps);
  const [count, setCount] = useState(0);

  const increment = useCallback(() => {
    setCount(count + steps);
    onChange && onChange(count + steps);
  }, [count, onChange]);

  return (
    <button onClick={increment}>
      {label} {count}
    </button>
  );
};

register(Counter, 'ric-counter', ['label', 'steps', 'onChange']);

E agora no HTML, basta usar o querySelector e atribuir a propriedade com a nossa função de callback:

<body>
  <ric-counter label="Custom count:" steps="2"></ric-counter>
  <script type="module" src="/src/main.tsx"></script>
  <script type="module">
    const counter = document.querySelector('ric-counter');
    counter.onChange = () => {
      console.log('counter changed');
    };
  </script>
</body>

Agora é só testar e ver um console.log sendo executado cada vez que clicar no botão. Você também pode ver o resultado final no meu Stackblitz.

Conclusão

Poder utilizar um web component direto no HTML abre portas pra muitos casos reais de uso. Você pode exportar os seus componentes pra serem incluídos em sites wordpress, ou até mesmo criar wrappers pra outros frameworks e reutilizar o seu código em diferentes interfaces.

Como eu disse antes nesse post, eu não acho que valha a pena desenvolver aplicações inteiras usando web components podendo usar direto o preact ou outro framework, mas se o seu contexto é libs, widgets, ou qualquer tipo de componente que é incorporado em outro website (por exemplo um chat), essa abordagem vai fazer muito sentido.

Se você curte o assunto e gostaria de ver mais posts desses por aqui, me avisa porque é algo que eu tenho gostado bastante de estudar, e acho que realmente vale a pena o investimento.

E se você não gostou de alguma coisa, ou tem alguma sugestão que possa fazer esse e os próximos artigos menores, lança aqui nos comentários também. Todo comentário é bem vindo e as críticas vão me ajudar a aprimorar os próximos posts 🙂

...

✅ Web Components com Preact


📈 42.21 Punkte

✅ 🚀 Building Dynamic Web Applications with Preact: A Lightweight Alternative to React


📈 31.6 Punkte

✅ Preact Setup: A Beginner's Guide


📈 27.99 Punkte

✅ Preact: Lightweight React Alternative


📈 27.99 Punkte

✅ Using Feature Flags in a Preact Application


📈 27.99 Punkte

✅ We Need To Talk About Preact (Fast Alternative To React?!)


📈 27.99 Punkte

✅ Type-Safe Eleventy Data Cascade Access with TSX and Preact Hooks


📈 27.99 Punkte

✅ Preact vs React: A Comparative Guide


📈 27.99 Punkte

✅ Lightning Web Components: Custom Nested Components


📈 24.84 Punkte

✅ React Components Explained: Function vs Class Components


📈 21.24 Punkte

✅ Embracing Modern React: Transitioning from Class Components to Functional Components


📈 21.24 Punkte

✅ React Components Explained: Function vs Class Components


📈 21.24 Punkte

✅ 🔄 Class Components vs Functional Components: A Lifecycle Journey in React 🔄


📈 21.24 Punkte

✅ React Components Explained: Function vs Class Components


📈 21.24 Punkte

✅ Converting React Class Components to Functional Components: A Checklist and Example


📈 21.24 Punkte

✅ Leveraging Dynamic Styles in React Components with Styled Components


📈 21.24 Punkte

✅ React Components 101: Building Reusable Components


📈 21.24 Punkte

✅ Next.js 14: Server Components and Client Components Explained


📈 21.24 Punkte

✅ Typescript for React Components (or How To Write Components in React The Right Way)


📈 21.24 Punkte

✅ How to use React Server Components components on Storybook 8


📈 21.24 Punkte

✅ React Controlled Components V/S Uncontrolled Components


📈 21.24 Punkte

✅ Medium CVE-2017-18604: Sitebuilder dynamic components project Sitebuilder dynamic components


📈 21.24 Punkte

✅ Function Components vs Class Components in React – With Examples


📈 21.24 Punkte

✅ Implementing Higher Order Components (HOC) for Functional Components in ReactJS


📈 21.24 Punkte

✅ Understanding Function Components vs Class Components in 100 seconds.


📈 21.24 Punkte

✅ Testing Components In Angular: NO ERRORS SCHEMA, Stub Components, and NgMocks


📈 21.24 Punkte

✅ Embracing Modern React: Transitioning from Class Components to Functional Components


📈 21.24 Punkte

✅ Web Development with Web Components: The New Way of Modularity


📈 17.82 Punkte

✅ Web Fundamentals: Web Components Part 2


📈 17.82 Punkte

✅ Web Components: The Secret Ingredient Helping Power The Web


📈 17.82 Punkte

✅ Web Components: The Secret Ingredient Helping Power The Web


📈 17.82 Punkte

✅ Microsoft Commerce Server 2000 Office Web Components privilege escalation


📈 14.22 Punkte

✅ 7 Web Components I maybe should have blogged about in 2023


📈 14.22 Punkte

✅ Web Components vs. Vanilla JavaScript: A Niche Comparison in Frontend Technologies


📈 14.22 Punkte











matomo

Datei nicht gefunden!