Otimizando Aplicativos React com APIs de Navegador Integradas

Otimizando Aplicativos React com APIs de Navegador Integradas

Em uma demonstração do React Compiler, um dos exemplos de código foi um manipulador de eventos que contém um estado React que depende se um elemento HTML está em foco. Na minha opinião, esse exemplo não demonstra o poder do React Compiler, mas mostra suas limitações. 

Veremos como podemos melhorar o código do nosso aplicativo React usando APIs de navegador integradas e ajudar o React Compiler a ter um desempenho melhor, contornando suas limitações. Também veremos APIs de navegador que podem ajudar a otimizar o desempenho dos aplicativos React em áreas além do escopo do React Compiler.

document.activeElement — para verificar se um elemento está em foco

Para verificar se um elemento está em foco, em vez de criar um estado React, podemos usar document.activeElement que retorna um elemento atualmente em foco. Podemos ler seu ID e compará-lo com um ID do nosso elemento.

:hover, :focus, :focus-within — para manipular hover, focus e outros estados

Às vezes, mergulhamos muito no React e JS e usamos o estado do React para lidar com estados de foco ou hover. Isso realmente resulta em re-renderizações desnecessárias e complexidade de código. Isso acontece especialmente frequentemente se o projeto usa bibliotecas Tailwind CSS ou Styled-components. Precisamos lembrar do poder de outras tecnologias disponíveis para nós, como CSS.

A melhor maneira de lidar com hover, focus e outros estados é usar pseudoclasses CSS correspondentes. O tratamento de Hover, Focus e outros estados Tailwind CSS deve ser feito usando modificadores especiais. Para estilização com base no estado pai, Tailwind CSS há uma classe especial group-{modifier}. Para estilizar com base em se algum dos elementos filhos está em foco, há uma pseudoclasse focus-within em CSS. Styled-components suporta a mesma sintaxe do CSS para manipular hover, foco e outros estados.

Saiba mais, <details>, <summary> — para obter a funcionalidade necessária pronta para uso

Com elementos HTML nativos, podemos obter muitas funcionalidades prontas para uso com ótimo desempenho e acessibilidade, sem a necessidade de escrever código extra ou adicionar estado extra no React.

Saiba mais — para seções dobráveis

Os estados Open/Close são manipulados automaticamente pelo navegador. Podemos usar CSS para estilizá-lo.

<select> — para menus suspensos

Os estados Abrir/Fechar são manipulados automaticamente pelo navegador. O menu suspenso é otimizado e responsivo mesmo em grandes listas de opções, é conveniente para uso em dispositivos desktop e móveis e é acessível imediatamente.

<form> e <button> — para formulários e envio de informações

Os elementos de formulário mantêm um estado interno sem a necessidade de criar um estado no React. Claro, para alguns cenários, podemos obter mais funcionalidade usando algumas bibliotecas de formulário de terceiros no React, mas não devemos subestimar o quanto podemos obter fora da caixa com elementos HTML nativos. Confira este exemplo no MDN com um formulário de pagamento totalmente funcional criado usando apenas HTML simples. Além disso, confira meu outro artigo para outro exemplo de como os formulários HTML podem ser usados para minimizar re-renderizações no React.

CustomEvent — para comunicação desacoplada entre componentes

Às vezes, precisamos que nossos componentes se comuniquem uns com os outros de forma independente, sem que tenhamos que criar um React.Context em algum lugar no topo do aplicativo. Podemos precisar disso se estivermos criando uma biblioteca de componentes ou se alguns de nossos componentes forem web-components. Para esse propósito, podemos usar CustomEvents.

Aqui está um exemplo de uso de um CustomEvent para implementar uma dica de ferramenta que fecha quando outra abre. Somente as dicas de ferramentas de abertura/fechamento são renderizadas novamente, em comparação com React.Context as quais, quando alteradas, fazem com que todos os componentes inscritos nela sejam renderizados novamente.

Transição e transformação CSS — para animações de alto desempenho

A propriedade transition em CSS nos permite criar animações. Devemos criar animações CSS usando apenas propriedades transform (scale, translate etc.) e não usando propriedades positioning (top/left/height/width) que causarão computação de layout contínua.

Antes de usar qualquer propriedade CSS para animação (exceto transform e opacity), precisamos determinar o impacto da propriedade no pipeline de renderização. Devemos evitar qualquer propriedade que acione layout ou paint, a menos que seja absolutamente necessário.

Os navegadores nos dão funcionalidade pronta para uso para criar animações e podem otimizar fluxos de renderização se as propriedades corretas forem usadas. Devemos sempre tentar criar nossas animações usando transições/animações CSS sempre que possível.

requestAnimationFrame, requestIdleCallback — para cálculos não bloqueantes

Se precisarmos alterar as propriedades CSS de um elemento usando JavaScript, devemos fazer isso com a API requestAnimationFrame, que ajudará a não bloquear outras operações do usuário, mas executá-las no final do quadro.

Tarefas JavaScript de longa duração e baixa prioridade devem ser divididas em tarefas menores e executadas dentro requestIdleCallback. Há um padrão "Idle Until Urgent".

Web Workers — para multithreading

Web Workers possibilitam executar uma operação de script em um thread de segundo plano separado do thread de execução principal (desta forma, eles são diferentes de requestAnimationFrame, requestIdleCallback que está sendo executado no thread principal). A vantagem disso é que o processamento trabalhoso pode ser executado em um thread separado, permitindo que o thread principal seja executado sem ser bloqueado/desacelerado.

Uma limitação dos Web workers é que eles não podem acessar o DOM diretamente. Mas eles podem se comunicar com o contexto da janela por meio de um pipeline de mensagens, o que significa que um web worker pode acessar o DOM indiretamente de uma forma.

Um dos exemplos de uso de Web Workers em aplicativos React pode ser um painel financeiro que processa grandes conjuntos de dados para gerar relatórios e gráficos complexos. Do aplicativo React, podemos enviar uma mensagem ao web worker para iniciar o cálculo. Assim que o worker terminar, ele envia o resultado de volta para o thread principal (nosso aplicativo React), onde podemos usá-lo para atualizar a UI (definir o estado do React).

Conclusão

O exemplo que mencionei no início do artigo foi usado para demonstrar como o React Compiler aplica a memorização para otimizar as re-renderizações quando o estado muda. Mas naquele exemplo, o estado não era necessário, e a mesma funcionalidade poderia ser alcançada usando apenas APIs de navegador integradas. Infelizmente, o React Compiler não sabe sobre isso, e ele tem que processar o código que foi dado como está. Se o código contiver um estado redundante, ele permanecerá lá. Quando o estado mudar, o React Compiler minimizará (não garantido) o quanto as re-renderizações do React e os cálculos relacionados à memorização ainda ocorrerão.

Então, o princípio principal da estruturação de estados no React: evitar estados redundantes, ainda vale a pena ser considerado. Além disso, quanto mais estados, mais dependências no código que precisam ser mantidas em sincronia e cobertas por testes.

  1. Confie nas APIs integradas do navegador o máximo possível, pois elas estão disponíveis "gratuitamente" (elas não aumentam o tamanho do pacote, etc.) e quase sempre são as mais bem otimizadas.
  2. Tente evitar criar estados no React para estados que podem ser manipulados pelo navegador.
  3. O React Compiler não será capaz de cobrir todas as otimizações do seu aplicativo. Muitas delas estão além do seu escopo. Mas muitas otimizações podem ser alcançadas usando APIs de navegador integradas.
  4. Antes de instalar uma nova dependência de projeto, verifique novamente se ela é realmente necessária. Com APIs de navegador integradas, podemos obter desempenho otimizado imediatamente.

Conteúdo Relacionado

Voltar para o blog

Deixe um comentário

Os comentários precisam ser aprovados antes da publicação.