Português

Desbloqueie o poder da lógica reutilizável em suas aplicações React com hooks personalizados. Aprenda a criar e usar hooks para um código mais limpo e manutenível.

Hooks Personalizados: Padrões de Lógica Reutilizável em React

Os React Hooks revolucionaram a forma como escrevemos componentes React ao introduzir o estado e funcionalidades de ciclo de vida aos componentes funcionais. Entre os muitos benefícios que oferecem, os hooks personalizados destacam-se como um mecanismo poderoso para extrair e reutilizar lógica entre múltiplos componentes. Este artigo de blog mergulhará fundo no mundo dos hooks personalizados, explorando os seus benefícios, criação e utilização com exemplos práticos.

O que são Hooks Personalizados?

Em essência, um hook personalizado é uma função JavaScript que começa com a palavra "use" e pode chamar outros hooks. Eles permitem extrair a lógica de um componente para funções reutilizáveis. Esta é uma forma poderosa de partilhar lógica com estado, efeitos secundários ou outros comportamentos complexos entre componentes sem recorrer a render props, componentes de ordem superior ou outros padrões complexos.

Características Principais dos Hooks Personalizados:

Benefícios de Usar Hooks Personalizados

Os hooks personalizados oferecem várias vantagens significativas no desenvolvimento com React:

Criando o Seu Primeiro Hook Personalizado

Vamos ilustrar a criação de um hook personalizado com um exemplo prático: um hook que rastreia o tamanho da janela.

Exemplo: useWindowSize

Este hook retornará a largura e a altura atuais da janela do navegador. Ele também atualizará esses valores quando a janela for redimensionada.

import { useState, useEffect } from 'react';

function useWindowSize() {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() => {
    function handleResize() {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }

    window.addEventListener('resize', handleResize);

    // Remove o ouvinte de evento na limpeza
    return () => window.removeEventListener('resize', handleResize);
  }, []); // O array vazio garante que o efeito seja executado apenas na montagem

  return windowSize;
}

export default useWindowSize;

Explicação:

  1. Importar Hooks Necessários: Importamos useState e useEffect do React.
  2. Definir o Hook: Criamos uma função chamada useWindowSize, respeitando a convenção de nomenclatura.
  3. Inicializar o Estado: Usamos useState para inicializar o estado windowSize com a largura e altura iniciais da janela.
  4. Configurar o Ouvinte de Evento: Usamos useEffect para adicionar um ouvinte de evento de redimensionamento (resize) à janela. Quando a janela é redimensionada, a função handleResize atualiza o estado windowSize.
  5. Limpeza (Cleanup): Retornamos uma função de limpeza do useEffect para remover o ouvinte de evento quando o componente é desmontado. Isto previne fugas de memória.
  6. Retornar Valores: O hook retorna o objeto windowSize, contendo a largura e altura atuais da janela.

Usando o Hook Personalizado num Componente

Agora que criamos o nosso hook personalizado, vamos ver como usá-lo num componente React.

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

function MyComponent() {
  const { width, height } = useWindowSize();

  return (
    

Largura da janela: {width}px

Altura da janela: {height}px

); } export default MyComponent;

Explicação:

  1. Importar o Hook: Importamos o hook personalizado useWindowSize.
  2. Chamar o Hook: Chamamos o hook useWindowSize dentro do componente.
  3. Aceder aos Valores: Desestruturamos o objeto retornado para obter os valores width e height.
  4. Renderizar os Valores: Renderizamos os valores de largura e altura na UI do componente.

Qualquer componente que use useWindowSize será atualizado automaticamente quando o tamanho da janela mudar.

Exemplos Mais Complexos

Vamos explorar alguns casos de uso mais avançados para hooks personalizados.

Exemplo: useLocalStorage

Este hook permite-lhe armazenar e recuperar dados facilmente do armazenamento local (local storage).

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  // Estado para armazenar o nosso valor
  // Passa o valor inicial para o useState para que a lógica seja executada apenas uma vez
  const [storedValue, setStoredValue] = useState(() => {
    try {
      // Obtém do armazenamento local pela chave
      const item = window.localStorage.getItem(key);
      // Analisa o JSON armazenado ou, se não houver, retorna o valor inicial
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // Se ocorrer um erro, também retorna o valor inicial
      console.log(error);
      return initialValue;
    }
  });

  // Retorna uma versão encapsulada da função setter do useState que...
  // ... persiste o novo valor no localStorage.
  const setValue = (value) => {
    try {
      // Permite que o valor seja uma função para que tenhamos a mesma API do useState
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      // Salva no armazenamento local
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
      // Salva o estado
      setStoredValue(valueToStore);
    } catch (error) {
      // Uma implementação mais avançada trataria o caso de erro
      console.log(error);
    }
  };

  useEffect(() => {
    try {
      const item = window.localStorage.getItem(key);
      setStoredValue(item ? JSON.parse(item) : initialValue);
    } catch (error) {
      console.log(error);
    }
  }, [key, initialValue]);

  return [storedValue, setValue];
}

export default useLocalStorage;

Utilização:

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

function MyComponent() {
  const [name, setName] = useLocalStorage('name', 'Convidado');

  return (
    

Olá, {name}!

setName(e.target.value)} />
); } export default MyComponent;

Exemplo: useFetch

Este hook encapsula a lógica para buscar dados de uma API.

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error(`Erro de HTTP! status: ${response.status}`);
        }
        const json = await response.json();
        setData(json);
        setLoading(false);
      } catch (error) {
        setError(error);
        setLoading(false);
      }
    }

    fetchData();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;

Utilização:

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

function MyComponent() {
  const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/todos/1');

  if (loading) return 

A carregar...

; if (error) return

Erro: {error.message}

; return (

Título: {data.title}

Concluído: {data.completed ? 'Sim' : 'Não'}

); } export default MyComponent;

Melhores Práticas para Hooks Personalizados

Para garantir que os seus hooks personalizados sejam eficazes e de fácil manutenção, siga estas melhores práticas:

Armadilhas Comuns a Evitar

Padrões Avançados

Composição de Hooks Personalizados

Hooks personalizados podem ser compostos para criar lógica mais complexa. Por exemplo, poderia combinar um hook useLocalStorage com um hook useFetch para persistir automaticamente os dados buscados no armazenamento local.

Partilha de Lógica entre Hooks

Se vários hooks personalizados partilharem lógica comum, pode extrair essa lógica para uma função de utilidade separada e reutilizá-la em ambos os hooks.

Usando Contexto com Hooks Personalizados

Hooks personalizados podem ser usados em conjunto com o Contexto do React para aceder e atualizar o estado global. Isto permite-lhe criar componentes reutilizáveis que estão cientes e podem interagir com o estado global da aplicação.

Exemplos do Mundo Real

Aqui estão alguns exemplos de como os hooks personalizados podem ser usados em aplicações do mundo real:

Exemplo: hook useGeolocation para aplicações interculturais como mapeamento ou serviços de entrega

import { useState, useEffect } from 'react';

function useGeolocation() {
  const [location, setLocation] = useState({
    latitude: null,
    longitude: null,
    error: null,
  });

  useEffect(() => {
    if (!navigator.geolocation) {
      setLocation({
        latitude: null,
        longitude: null,
        error: 'A geolocalização não é suportada por este navegador.',
      });
      return;
    }

    const watchId = navigator.geolocation.watchPosition(
      (position) => {
        setLocation({
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
          error: null,
        });
      },
      (error) => {
        setLocation({
          latitude: null,
          longitude: null,
          error: error.message,
        });
      }
    );

    return () => navigator.geolocation.clearWatch(watchId);
  }, []);

  return location;
}

export default useGeolocation;

Conclusão

Os hooks personalizados são uma ferramenta poderosa para escrever código React mais limpo, reutilizável e manutenível. Ao encapsular lógica complexa em hooks personalizados, pode simplificar os seus componentes, reduzir a duplicação de código e melhorar a estrutura geral das suas aplicações. Adote os hooks personalizados e desbloqueie o seu potencial para construir aplicações React mais robustas e escaláveis.

Comece por identificar áreas na sua base de código existente onde a lógica está a ser repetida em múltiplos componentes. De seguida, refatore essa lógica para hooks personalizados. Com o tempo, irá construir uma biblioteca de hooks reutilizáveis que acelerará o seu processo de desenvolvimento e melhorará a qualidade do seu código.

Lembre-se de seguir as melhores práticas, evitar armadilhas comuns e explorar padrões avançados para tirar o máximo proveito dos hooks personalizados. Com prática e experiência, tornar-se-á um mestre em hooks personalizados e um desenvolvedor React mais eficaz.