Esquecemos a delegação em JavaScript. Delegação de evento em reagir

Olá pessoal. Este artigo é sobre delegação de eventos em JavaScript e sua implementação em react.js.



Sobre o que é realmente? Porque e porque?


Para começar, vamos discutir brevemente:


  1. o que é um evento;
  2. como a distribuição ocorre;
  3. Processando DOM Nível 2 com um exemplo em JavaScript;

E finalmente: por que não esquecer a delegação no React.


Evento


JavaScript e HTML interagem entre si por meio de eventos. Cada evento serve para informar ao JavaScript que algo aconteceu na janela do documento ou do navegador. Para capturar esses eventos, precisamos de listeners (listeners), manipuladores que são acionados no evento de um evento.


Propagação de Eventos


Ordem. Resolvendo o problema: como entender a que parte da página o evento pertence? Dois métodos foram implementados: no Internet Explorer, “evento com bolhas”, e no Netscape Communicator, “evento com conexão”.


Evento borbulhando


Nesse caso, o evento é acionado no nó mais profundo da árvore de documentos, após o qual sobe pela hierarquia até a própria janela.


<!DOCTYPE html> <html> <head> <title>Some title</title> </head> <body> <div id="myDiv">Click Me</div> </body> </html> 

Nesse caso, haverá a seguinte ordem:


  1. elemento div
  2. elemento do corpo
  3. elemento html
  4. documento
  5. janela

Agora, a navegação é suportada por todos os navegadores modernos, embora com implementações diferentes.

No caso de interceptação de eventos, o oposto é verdadeiro:


  1. janela
  2. documento
  3. elemento html
  4. elemento do corpo
  5. elemento div

Acreditava-se que o evento pudesse ser processado antes de atingir o elemento de destino (conforme decidido no Netscape posteriormente, todos os navegadores modernos).

Como resultado, temos a seguinte estrutura para distribuir eventos DOM:


  1. janela
  2. documento
  3. elemento html
  4. elemento do corpo // a fase de interceptação termina
  5. elemento div // fase de destino
  6. elemento do corpo // começa a fase de subida
  7. elemento html
  8. documento
  9. janela

Esse esquema é dividido em três fases: a fase de interceptação - o evento pode ser interceptado antes de atingir o elemento, a fase de destino - processada pelo elemento de destino e a fase de subida - para executar qualquer ação final em resposta ao evento.


Então, passamos ao processamento de eventos


Vamos ver um exemplo típico de manipulação de eventos em JavaScript.


 const btn = document.getElementById('myDiv') btn.addEventListener("click", handler) // some code btn.removeEventListener("click", handler) 

Tudo não seria nada, mas aqui lembramos do nosso querido IE, que assina eventos usando o attachEvent e remove o destacador. E você pode se inscrever no evento várias vezes. E não esqueça que, ao assinar uma função anônima, não temos a oportunidade de cancelar a inscrição.


Mas não somos g * codificadores externos. Vamos fazer tudo de acordo com o cânon:


 var EventUtil = { addHandler: function (elem, type, handler) { if (elem.addEventListener) { elem.addEventListener(type, handler, false) } else if (elem.attachEvent) { elem.attachEvent("on" + type, handler) } else { elem["on" = type] = hendler } }, removeHandler: function (elem, type, handler) { if (elem.removeEventListener) { elem.removeEventListener(type, handler, false) } else if (elem.detachEvent) { elem.detachEvent("on" + type, handler) } else { elem["on" = type] = null } } } 

Tão bom, mas e o objeto de evento? Afinal, no IE não há .target .srcElement, preventDefault? no returnValue = false. Mas não há nada para adicionar alguns métodos:


 var EventUtil = { addHandler: function (elem, type, handler) { if (elem.addEventListener) { elem.addEventListener(type, handler, false) } else if (elem.attachEvent) { elem.attachEvent("on" + type, handler) } else { elem["on" = type] = hendler } }, getEvent: function (event) { return event ? event : window.event }, getTarget: function (event) { return event.target || event.srcElement }, preventDefault: function (event) { if (event.preventDefault) { event.preventDefault() } else { event.returnValue = false } }, removeHandler: function (elem, type, handler) { if (elem.removeEventListener) { elem.removeEventListener(type, handler, false) } else if (elem.detachEvent) { elem.detachEvent("on" + type, handler) } else { elem["on" = type] = null } }, stopPropagation: function (event) { if (event.stopPropagation) { event.stopPropagation() } else { event.cancelBubble = true } } } 

Etc. etc. e estas são todas as danças.


Bem, estamos bem, resolvemos todos os problemas, está tudo bem. É verdade que o código saiu bastante complicado. Agora imagine que precisamos de muitas assinaturas para muitos elementos. Uau, isso levará algumas linhas de código. Um exemplo:


 <ul> <li id="id1">go somewhere</li> <li id="id2">do something</li> <li id="some-next-id">next</li> </ul> var item1 = document.getElementById('id1') var item2 = document.getElementById('id2') var itemNext = document.getElementById('some-next-id') EventUtil.addHandler(item1, "click", someHandle) EventUtil.addHandler(item2, "click", someHandle2) EventUtil.addHandler(itemNext, "click", someHandle3) 

E assim, para cada elemento, e não devemos esquecer de excluir, trabalhar com o alvo e similares


E aqui a delegação de eventos vem em nosso auxílio.


Tudo o que precisamos fazer é conectar um único manipulador ao ponto mais alto da árvore DOM:


 <ul id="main-id"> //  id    <li id="id1">go somewhere</li> <li id="id2">do something</li> <li id="some-next-id">next</li> </ul> var list = document.getElementById('main-id') EventUtil.addHandler(list, "click", function(event) { event = EventUtil.getEvent(event) var target = EventUtil.getTarget(event) switch(target.id) { case "id1": //  -    id1 break case "id2": //  -    id1 break case "some-next-id": //  -    break } }) 

Como resultado, temos apenas um manipulador na memória e a propriedade id pode ser usada para a ação desejada. Menos consumo de memória melhora o desempenho geral da página. Registrar um manipulador de eventos requer menos tempo e menos chamadas para o DOM. A exceção é talvez o mouse e o mouseout, com eles tudo é um pouco mais complicado.


Agora, o que dizer do React


Tudo sobre a compatibilidade entre navegadores para nós já foi feito por pessoas do facebook. Todos os nossos manipuladores de eventos recebem uma instância de SyntheticEvent . Que cuida de nós reutilizando eventos do pool, removendo todas as propriedades após chamar o manipulador.


Bom


No entanto, um manipulador extra é um manipulador extra. Eu me encontrei várias vezes e me arrependo, escrevi esse tipo de código:


 class Example extends React.Component { handleClick () { console.log('click') } render () { return ( <div> {new Array(20).fill().map((_, index) => <div key={index} // elem.id id={index} // elem.id onClick={() => console.log('click')} /> )} </div> ) } } 

O exemplo mostra o caso em que existe algum tipo de planilha com número n de elementos e, portanto, com número n de registros de manipuladores.


Vamos correr, vá para a página e verifique quantos manipuladores estão em ação no momento. Para isso, encontrei um bom script:


 Array.from(document.querySelectorAll('*')) .reduce(function(pre, dom){ var clks = getEventListeners(dom).click; pre += clks ? clks.length || 0 : 0; return pre }, 0) 

Funciona no Chrome dev-tool.


E agora delegamos tudo isso ao div principal e aplausos, apenas otimizamos nosso aplicativo n = array.length times. Exemplo de código abaixo:


 class Example extends React.Component { constructor () { super() this.state = { useElem: 0 } } handleClick (elem) { var id = elem.target.id this.setState({ useElem: id }) } render () { return ( <div onClick={this.handleClick}> {new Array(20).fill().map((_, index) => <div key={index} // elem.id id={index} // elem.id useElem={index === this.state.useElem} /> )} </div> ) } } 

A delegação é uma boa ferramenta para processar um grande número de assinaturas e, no caso de renderização dinâmica e redesenhos frequentes, é simplesmente insubstituível. Tenha pena dos recursos do usuário, eles não são ilimitados.


Este artigo é baseado em um livro JavaScript para desenvolvedores profissionais da Web, escrito por Nicholas Zakas.


Muito obrigado pela atenção. Se você tem algo para compartilhar ou encontrar algum tipo de falha, talvez um erro ou apenas uma pergunta, então escreva nos comentários. Ficarei feliz em qualquer feedback!

Source: https://habr.com/ru/post/pt467361/


All Articles