Web Components, atributos e métodos de reação (parte 2)

gabrieljm

Gabriel José

Posted on March 2, 2021

Web Components, atributos e métodos de reação (parte 2)

Essa é a segunda parte da série de tutoriais sobre Web Components, não deixe de ver a primeira parte que mostro o que são e como criar Web Components. Nesse tutorial vamos ver como criar uma interface de programação(API) para nossos componentes e veremos como funcionam suas funções reação.

Definindo a API do elemento

Como comentado antes, assim que o elemento estende de HTMLElement é garantido que ele herde a API DOM que existe em comum entre os elementos HTML, isso também significa que todo atributo/propriedade e métodos da classe farão parte dessa API DOM também.

Vamos, criar um <text-hider>, um elemento simples que terá um X para esconder ou mostrar um texto.

class TextHider extends HTMLElement {
  get show() {
    return this.hasAttribute('show')
  }

  set show(value) {
    if(typeof value !== 'boolean') {
      throw new TypeError(
        'text-hider "show" attribute only accepts boolean values'
      )
    }

    if(value) {
      this.setAttribute('show', '')
      this.querySelector('[text]').innerText = 'Showing the text'
    } else {
      this.removeAttribute('show')
      this.querySelector('[text]').innerText = ''
    }
  }

  constructor() {
    super()

    this.innerHTML = `
      <span>X</span>
      <span text>${this.show ? 'Showing the text' : ''}</span>
    `

    this.querySelector('span').addEventListener('click', () => {
      this.show = !this.show
    })
  }
}

customElements.define('text-hider', TextHider)
Enter fullscreen mode Exit fullscreen mode

Repare no código acima que as funções getter e setter show representam a propriedade show que pode ser adicionada a tag text-hider. Ela pode ser acessa de forma programática da seguinte maneira:

const textHider = new TextHider()
textHider.show = true
console.log(textHider.show) // true
Enter fullscreen mode Exit fullscreen mode

Repare também em dois detalhes, um deles é que foi utilizado o método querySelector atrelado ao this, isso acontece porque o this dentro da classe se refere diretamente ao elemento que estamos criando e que como dito antes ele possui toda a API DOM comum aos elementos HTML. O outro detalhe se encontra dentro do if no método setter do atributo show, em que alteramos o innerText do segundo elemento span dependendo se o valor recebido era verdadeiro ou falso, fazendo isso somos capazes de ter uma certa reatividade no elemento, fazendo com que ele reaja à toda vez em que o valor de show é alterado.

Métodos de reação

Elementos customizados podem definir métodos de ciclo de vida especiais, que são executados em momentos específicos da sua existência. Eles são conhecidos como métodos de reação.

  • constructor: chamado quando um novo elemento é instanciado ou aprimorado. Útil para definir estados iniciais, adicionar eventos e afins.
  • connectedCallback: chamado quando o elemento é inserido dentro do DOM, sendo o light DOM ou o shadow DOM de outro elemento(depois vamos falar sobre light DOM e shadow DOM). Útil para rodar código preparatório ou que receba alguma condição externa ao entrar no DOM.
  • disconnectedCallback: chamado quando o elemento é removido do DOM. Útil para rodar códigos de limpeza, como remoção de ouvintes de evento.
  • attributeChangedCallback: chamando quando algum atributo observado é adicionado, alterado ou removido. Esses atributos são listados no array retornado no método getter estático observedAttributes, logo mais falaremos sobre ele. Esse é o único método que recebe parâmetros, sendo o primeiro o nome do atributo alterado, o segundo sendo o valor antigo do atributo e o último sendo o novo valor.
  • adoptedCallback: chamado quando o elemento é movido de documento. (por exemplo, quando alguém invoca document.adoptNode(el)).

Esses métodos de reação, são síncronos e serão imediatamente invocados quando as condições de invocação forem satisfeitas.
Não é necessário definir todos esses métodos, utilize deles quando fizer sentido.

class MeuComponente extends HTMLElement {
  static get observedAttributes() {
    return []
  }

  constructor() {
    super()
  }

  connectedCallback() {...}

  disconnectedCallback() {...}

  attributeChangedCallback(name, oldValue, newValue) {...}

  adoptedCallback() {...}
}
Enter fullscreen mode Exit fullscreen mode

Propriedades e atributos

Como vimos antes podemos definir métodos para ter acesso aos atributos de um elemento de forma programática bem simples, além de ser um certo padrão de acesso aos atributos nos elementos HTML. Vamos usar uma div de exemplo alterando os atributos hidden e id:

div.id = 'my-id'
div.hidden = true
Enter fullscreen mode Exit fullscreen mode

A atribuição pelo JS, é refletida no HTML:

<div id="my-id" hidden>
Enter fullscreen mode Exit fullscreen mode

Isso pode ser chamado de "refletindo propriedades à atributos", lembrar desses detalhes é muito importante para ter a noção de que nosso elemento definido no JS está em sincronia com sua representação no DOM e isso pode até mesmo afetar estilizações que, por exemplo, usem seletores de atributos ([attribute]).

Observando mudanças à atributos

Adicionar atributos a um elemento é uma forma comum de definir o estado inicial daquele elemento. Como vimos podemos adicionar um método attributeChangedCallback para que nosso elemento reaja a mudança nos atributos, porém ele somente será invocado caso o nome do atributo esteja no array retornado por observedAttributes e este método deve ser obrigatoriamente static get.

static get observedAttributes() {
  return ['attribute']
}
Enter fullscreen mode Exit fullscreen mode

Isso é implementado dessa maneira por questão de performance, para que seu código não seja invocado de formas desnecessárias, como por exemplo, quando mudar o atributo class e ser invocado attributeChangedCallback.


Referências

https://developers.google.com/web/fundamentals/web-components/customelements

Conclusão

Essas são as formas como podemos manipular as reações dos elementos e seus atributos. O conteúdo dessa parte é de certa forma simples, porém eu aconselho muito a treinar bastante e ver como os elementos reagem para entender cada detalhe melhor. Espero que gostem e qualquer dúvida deixe um comentário e até logo!!!

💖 💪 🙅 🚩
gabrieljm
Gabriel José

Posted on March 2, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related