Uma Abordagem para Cache de Componentes em React

Em aplicações React, frequentemente encontramos situações onde é necessário manter o estado de componentes específicos mesmo quando não estão visíveis. Uma abordagem comum envolve utilizar o componente Route com o método children para alternar a exibição entre block e none. No entanto, essa técnica apresanta limitações, pois depende do sistema de rotas e só é aplicável a páginas inteiras, não a componentes individuais.

Este artigo apresenta uma alternativa que permite preservar o estado de componentes durante seu ciclo de vida, mesmo quando são temporariamente removidos da árvore DOM.

Conceito Fundamental

A solução proposta baseia-se em capturar o estado de um componente antes de seu desmontagem e restaurá-lo quando o componente for re-renderizado. Essa abordagem garante que o componente retome exatamente onde parou, mantendo toda a sua integridade de estado.

Implementação

Vamos criar um Higher-Order Component (HOC) que encapsulará nossa lógica de cache. Este HOC será responsável por:

  • Interceptar o ciclo de vida do componente encapsulado
  • Armazenar o estado antes do desmontagem
  • Restaurar o estado durante a montagem subsequente

Código do HOC de Cache

const preservarEstado = (ComponenteAlvo) => {
  const armazenamentoCache = {};
  
  return class ComponentePreservado extends React.Component {
    constructor(props) {
      super(props);
      this.referenciaInterna = null;
    }
    
    componentDidMount() {
      if (this.referenciaInterna) {
        const estadoAtual = this.referenciaInterna.state;
        this.referenciaInterna.setState({
          ...estadoAtual,
          ...armazenamentoCache[ComponenteAlvo.name]
        });
      }
    }
    
    componentWillUnmount() {
      if (this.referenciaInterna) {
        armazenamentoCache[ComponenteAlvo.name] = {
          ...this.referenciaInterna.state
        };
      }
    }
    
    render() {
      return (
        <ComponenteAlvo 
          ref={ref => this.referenciaInterna = ref} 
          {...this.props} 
        />
      );
    }
  };
};

export default preservarEstado;

Exemplo de Uso

Vamos criar um componente contador que demonstrará como o estado é preservado:

import React from 'react';
import preservarEstado from './preservarEstado';

class ContadorExemplo extends React.Component {
  estadoInicial = {
    valor: 0,
    historico: []
  };

  constructor(props) {
    super(props);
    this.state = this.estadoInicial;
  }

  incrementar = () => {
    const novoValor = this.state.valor + 1;
    this.setState({
      valor: novoValor,
      historico: [...this.state.historico, novoValor]
    });
  };

  render() {
    const { valor, historico } = this.state;
    
    return (
      <div className="componente-contador">
        <h3>Componente com Cache de Estado</h3>
        <p>Valor atual: {valor}</p>
        <button onClick={this.incrementar}>
          Incrementar
        </button>
        <div>
          <h4>Histórico:</h4>
          <ul>
            {historico.map((item, indice) => (
              <li key={indice}>{item}</li>
            ))}
          </ul>
        </div>
      </div>
    );
  }
}

export default preservarEstado(ContadorExemplo);

Limitações e Considerações

É importante notar que esta implementação atualmente só funciona com componentes baseados em classes (herdados de React.Component). Componentes funcionais que utilizam Hooks não são suportados, pois:

  • O estado em componentes funcionais é gerenciado internamente pelo React
  • Não existe uma referência direta ao componente para acessar seu estado
  • A API de Hooks não expõe métodos para capturar todo o estado de uma vez

Para componentes funcionais, seria necessário uma abordagem completamente diferente, possivelmente envolvendo o uso de useRef e useState de forma personalizada.

Utilização Prática

Esta solução já está disponível como pacote npm. Para utilizá-la em seu projeto:

npm install react-component-cache --save

Após a instalação, importe o HOC e aplique-o aos componentes que precisam de cache de estado:

import React from 'react';
import withCache from 'react-component-cache';

class MeuComponente extends React.Component {
  // ... implementação do componente
}

export default withCache(MeuComponente);

Tags: React componentes cache Otimização desempenho

Publicado em 7-4 23:11