React Hook - useInterval


O hook personalizado useInterval é uma implementação que aborda um desafio comum ao utilizar o setInterval em conjunto com os React Hooks. O problema principal reside na natureza imperativa do setInterval, que muitas vezes entra em conflito com o modelo de programação declarativa dos React Hooks.

Ao usar o setInterval de maneira direta em um componente funcional do React, enfrentamos problemas relacionados à reexecução dos efeitos após cada renderização. Isso ocorre porque o setInterval não se encaixa perfeitamente no modelo de programação declarativa dos React Hooks. A reexecução frequente de efeitos pode causar interferências no timing do setInterval, resultando em comportamentos inesperados.

Vamos analisar a implementação do useInterval passo a passo:

1. Importação de Hooks e criação do Hook

import { useEffect, useRef } from 'react';
 
function useInterval(callback, delay) {
 // Implementação do hook aqui
}

2. Utilização do useRef

const savedCallback = useRef();

O useRef é utilizado para manter uma referência mutável persistente entre as renderizações do componente. Neste caso, ele é usado para armazenar a função de callback do intervalo.

3. Efeito para salvar o callback atual

useEffect(() => {
 savedCallback.current = callback;
}, [callback]);

Este efeito é acionado sempre que o callback muda. Ele atualiza o current de savedCallback com a função de callback mais recente.

4. Efeito para configurar o intervalo

useEffect(() => {
 function tick() {
   savedCallback.current();
 }
 
 if (delay !== null) {
   let id = setInterval(tick, delay);
   return () => clearInterval(id);
 }
}, [delay]);

Este segundo efeito é acionado sempre que o delay muda. Se delay não for nulo, ele configura um intervalo chamando o tick (que, por sua vez, chama o savedCallback). Além disso, retorna uma função de limpeza que é executada quando o componente é desmontado, garantindo que o intervalo seja limpo.

5. Uso do Hook em um componente

// useInterval.js
import { useEffect, useRef } from 'react';
 
function useInterval(callback, delay) {
  const savedCallback = useRef();
 
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);
 
  useEffect(() => {
    function tick() {
      savedCallback.current();
    }
 
    if (delay !== null) {
      let id = setInterval(tick, delay);
 
      return () => clearInterval(id);
    }
  }, [delay]);
}
import React, { useState } from 'react';
import useInterval from './useInterval';
 
function Counter() {
  const [count, setCount] = useState(0);
 
  useInterval(() => {
    setCount(count + 1);
  }, 1000);
 
  return <h1>{count}</h1>;
}
 
export default Counter;

O useInterval encapsula a complexidade associada ao uso de setInterval em um ambiente React, garantindo que o intervalo seja tratado corretamente durante o ciclo de vida do componente. Ele fornece uma maneira mais declarativa e fácil de lidar com operações baseadas em intervalo de tempo em seus componentes React.

Referências