DEV Community

Cover image for Explorando os Hooks Adicionais do React: Exemplos e Casos de Uso
Jhonata Vinicius Da Silva Araujo
Jhonata Vinicius Da Silva Araujo

Posted on • Updated on

Explorando os Hooks Adicionais do React: Exemplos e Casos de Uso

Introdução:

O React é uma biblioteca JavaScript amplamente utilizada para a construção de interfaces de usuário interativas. Desde a introdução dos Hooks no React 16.8, os desenvolvedores têm desfrutado de uma maneira mais simples e eficiente de compartilhar lógica entre componentes funcionais.

Além dos Hooks básicos, como useState, useEffect e useContext, o React também oferece Hooks adicionais que fornecem funcionalidades extras.

Neste artigo, exploraremos esses Hooks adicionais, discutiremos seus casos de uso e será fornecido exemplos práticos.

useReducer:

O Hook useReducer é uma alternativa ao useState quando se lida com estados mais complexos que envolvem múltiplas transições. Ele aceita um reducer e um estado inicial, retornando o estado atual e uma função dispatch para disparar ações.

É útil quando se trabalha com lógica de estado mais avançada, como gerenciamento de formulários ou estados de aplicativos complexos.

Exemplo:

import React, { useReducer } from 'react';

const initialState = { count: 0 };

const reducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
};

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  );
};

Enter fullscreen mode Exit fullscreen mode

useRef:

O Hook useRef retorna um objeto mutável que persiste durante todo o ciclo de vida do componente. É útil para acessar e manter uma referência a um elemento do DOM, armazenar valores mutáveis entre renderizações ou para armazenar qualquer valor que precise ser persistido durante o ciclo de vida do componente.

Exemplo:

import React, { useRef } from 'react';

const InputWithFocus = () => {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  );
};

Enter fullscreen mode Exit fullscreen mode

useMemo:

O Hook useMemo é usado para memorizar o resultado de uma função de cálculo pesado e evitar recalculá-la em cada renderização.

Ele recebe uma função de cálculo e um array de dependências e retorna o valor memorizado. É útil quando o cálculo é computacionalmente intensivo e os valores de entrada não mudam com frequência.

Exemplo:

import React, { useMemo } from 'react';

const ExpensiveCalculation = () => {
  const result = useMemo(() => {
    // Cálculo pesado
    return performExpensiveCalculation();
  }, [dependencies]);

  return <div>Result: {result}</div>;
};

Enter fullscreen mode Exit fullscreen mode

useCallback:

O hook useCallback é usado para memorizar uma função e evitar a criação desnecessária de uma nova instância dessa função a cada renderização do componente.

Ele é útil quando você deseja otimizar o desempenho de componentes que dependem de funções que não precisam ser recriadas sempre que o componente é renderizado.

Vamos explorar abaixo alguns casos de uso e fornecer um exemplo prático.

Casos de Uso:

  1. Passar uma função para um componente filho: Quando um componente pai passa uma função para um componente filho como prop, o uso do useCallback pode evitar que a função seja recriada a cada renderização do componente pai, garantindo que o componente filho só seja atualizado quando realmente necessário.
  2. Otimizar a criação de manipuladores de eventos: Em componentes que possuem eventos que disparam ações complexas ou fazem cálculos intensivos, o useCallback pode ser usado para garantir que o manipulador de eventos seja criado apenas uma vez, evitando renderizações desnecessárias.

Exemplo:

import React, { useCallback, useState, memo } from 'react';

const ChildComponent = memo(({ handleClick }) => {
  // Componente filho que é renderizado quando o handleClick é atualizado
  return <button onClick={handleClick}>Click Me</button>;
});

const ParentComponent = () => {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    setCount((prevCount) => prevCount + 1);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <ChildComponent handleClick={handleClick} />
    </div>
  );
};

Enter fullscreen mode Exit fullscreen mode

No exemplo acima, o hook useCallback é usado para memorizar a função handleClick no componente pai. Dessa forma, mesmo que o componente pai seja renderizado várias vezes, a função handleClick não será recriada, garantindo que o componente filho seja renderizado apenas quando o estado count for atualizado.

useImperativeHandle:

O hook useImperativeHandle é usado para expor funções e propriedades específicas de um componente funcional para componentes pai.

Ele permite que você controle a instância do componente filho e exponha métodos personalizados para serem acessados externamente.

Vamos explorar abaixo alguns casos de uso e fornecer um exemplo prático.

Casos de Uso:

  1. Integração com bibliotecas de terceiros: Em alguns casos, você pode precisar integrar seu componente funcional com uma biblioteca externa que requer o acesso direto a alguns métodos ou propriedades do componente. O useImperativeHandle permite que você exponha apenas o que é necessário, mantendo o controle sobre a interface externa do componente.
  2. Componentes customizados com APIs específicas: Se você está criando um componente personalizado que precisa ser controlado externamente, como um componente de formulário que precisa ser validado ou enviado, o useImperativeHandle pode ser usado para expor métodos relevantes para o controle externo.

Exemplo:

import React, { useRef, useImperativeHandle, forwardRef } from 'react';

// Componente filho que deseja expor um método
const ChildComponent = forwardRef((props, ref) => {
  const inputRef = useRef(null);

  useImperativeHandle(ref, () => ({
    focusInput: () => {
      inputRef.current.focus();
    },
  }));

  return <input ref={inputRef} type="text" />;
});

// Componente pai que acessa o método exposto pelo componente filho
const ParentComponent = () => {
  const childRef = useRef(null);

  const handleClick = () => {
    childRef.current.focusInput();
  };

  return (
    <div>
      <ChildComponent ref={childRef} />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  );
};

Enter fullscreen mode Exit fullscreen mode

No exemplo acima, o hook useImperativeHandle é usado no componente filho para expor o método focusInput. O componente filho utiliza o hook useRef para criar uma referência ao elemento de input e, em seguida, o hook useImperativeHandle é usado para expor o método focusInput através da referência passada como segundo argumento.

No componente pai, um botão é renderizado e, quando clicado, chama o método focusInput exposto pelo componente filho através da referência childRef. Dessa forma, é possível acessar o elemento de input no componente filho e aplicar o foco diretamente.

useLayoutEffect:

O hook useLayoutEffect é bastante semelhante ao useEffect, porém é sincronizado com o ciclo de renderização do React, o que significa que ele é executado imediatamente após as mudanças no DOM serem aplicadas, mas antes do browser concluir a pintura da tela.

Ele é útil em casos em que você precisa realizar tarefas de manipulação de layout que dependem das medidas ou posições dos elementos na tela.

Vamos explorar abaixo alguns casos de uso e fornecer um exemplo prático.

Casos de Uso:

  1. Manipulação de medidas e posições de elementos: O useLayoutEffect pode ser usado quando você precisa obter as medidas ou posições de elementos no DOM que foram atualizadas após a renderização do componente. Por exemplo, se você precisa calcular a altura ou a largura de um elemento ou precisa posicionar um elemento com base em outras medidas.
  2. Atualização de animações ou efeitos visuais: Quando você deseja criar animações ou efeitos visuais que dependem de informações atualizadas de layout, como transições suaves ou animações que envolvem mudanças na posição ou tamanho dos elementos, o useLayoutEffect pode ser usado para garantir que essas atualizações sejam aplicadas antes da pintura da tela.
  3. Interações com bibliotecas externas: Se você está integrando seu componente com uma biblioteca externa que espera que o DOM esteja atualizado antes de realizar determinadas ações, o useLayoutEffect pode ser útil para garantir que as mudanças no DOM sejam aplicadas antes da interação com a biblioteca.

Exemplo:

import React, { useLayoutEffect, useRef } from 'react';

const ComponentWithLayoutEffect = () => {
  const elementRef = useRef(null);

  useLayoutEffect(() => {
    // Obtém as medidas do elemento após a atualização do DOM
    const { width, height } = elementRef.current.getBoundingClientRect();

    // Atualiza algum estado ou realiza alguma ação com base nas medidas obtidas
    console.log(`Largura: ${width}px, Altura: ${height}px`);
  });

  return <div ref={elementRef}>Exemplo de Componente com useLayoutEffect</div>;
};

Enter fullscreen mode Exit fullscreen mode

No exemplo acima, o hook useLayoutEffect é usado para realizar uma ação após a atualização do DOM. O elemento <div> é referenciado usando o hook useRef, permitindo o acesso ao elemento em questão.

Dentro do useLayoutEffect, as medidas do elemento são obtidas usando o método getBoundingClientRect(), que retorna um objeto contendo informações sobre as dimensões e a posição do elemento no viewport.

Neste exemplo, estamos apenas exibindo as medidas no console, mas você pode realizar qualquer ação necessária com base nessas medidas.

É importante ressaltar que o useLayoutEffect é síncrono e bloqueante, o que significa que ele pode causar um atraso na renderização do componente. Portanto, é importante usá-lo com cuidado e considerar se o useEffect seria mais adequado em determinadas situações.

useDebugValue:

O hook useDebugValue é um hook de diagnóstico do React que permite fornecer um rótulo personalizado para um valor customizado, facilitando a identificação e depuração de componentes durante o desenvolvimento.

Ele não tem impacto na renderização ou funcionalidade do componente, mas fornece informações úteis ao utilizar ferramentas de desenvolvimento.

Casos de Uso:

  1. Exibição de informações personalizadas: O useDebugValue pode ser usado para exibir informações personalizadas sobre um valor durante a depuração. Isso é especialmente útil quando você possui um valor complexo ou derivado que deseja inspecionar facilmente enquanto depura seu componente.
  2. Identificação de componentes em ferramentas de desenvolvimento: Ao usar ferramentas de desenvolvimento que suportam o hook useDebugValue , você pode fornecer um rótulo significativo para um componente, tornando mais fácil identificar e distinguir componentes específicos na árvore de componentes.
  3. Visualização de estado interno: Se você tiver algum estado interno no componente que não é diretamente visível no componente renderizado, o useDebugValue pode ser usado para expor esse estado durante a depuração, permitindo uma melhor compreensão do estado interno do componente.

Exemplo:

import React, { useDebugValue, useState } from 'react';

const ComponentWithDebugValue = () => {
  const [count, setCount] = useState(0);

  useDebugValue(`Count: ${count}`);

  const increment = () => {
    setCount(prevCount => prevCount + 1);
  };

  return (
    <div>
      <button onClick={increment}>Increment</button>
      <p>Count: {count}</p>
    </div>
  );
};

Enter fullscreen mode Exit fullscreen mode

No exemplo acima, o hook useDebugValue é usado para fornecer um rótulo personalizado para o valor count. Isso significa que, ao inspecionar o componente em ferramentas de desenvolvimento, o rótulo "Count: {valor}" será exibido, facilitando a identificação do estado do contador durante a depuração.

Ao clicar no botão "Increment", o estado count é atualizado e o componente é renderizado novamente. Durante a renderização, o hook useDebugValue garante que o rótulo personalizado seja atualizado, permitindo que você acompanhe facilmente o valor atualizado do contador durante a depuração.

Embora o exemplo acima seja simples, o useDebugValue é particularmente útil em cenários mais complexos, onde você pode ter valores personalizados ou derivados que precisam ser monitorados e inspecionados durante o desenvolvimento.

useDeferredValue:

O hook useDeferredValue é um hook introduzido no React 18 que permite atrasar a atualização de um valor de estado durante a renderização. Ele é útil para otimizar o desempenho de componentes que possuem valores de estado que não precisam ser atualizados imediatamente.

Casos de Uso:

  1. Atualizações não críticas: Se você tiver um valor de estado que é atualizado com frequência, mas as atualizações não são críticas para a renderização imediata do componente, você pode usar o useDeferredValue para atrasar a atualização desse valor. Isso pode melhorar o desempenho, reduzindo a frequência de atualizações e renderizações desnecessárias.
  2. Animações suaves: O useDeferredValue é especialmente útil para criar animações suaves em componentes. Você pode atrasar a atualização do valor de estado usado para controlar a animação, garantindo que a animação seja executada de forma mais fluida e sem interrupções.
  3. Carregamento de dados assíncronos: Se você estiver buscando dados assíncronos e deseja evitar atualizações rápidas do estado enquanto os dados estão sendo buscados, o useDeferredValue pode ser usado para atrasar a atualização do estado até que os dados sejam completamente carregados, evitando renderizações desnecessárias.

Exemplo:

import React, { useState, useDeferredValue } from 'react';

const ComponentWithDeferredValue = () => {
  const [count, setCount] = useState(0);

  const deferredCount = useDeferredValue(count, { timeoutMs: 1000 });

  const increment = () => {
    setCount(prevCount => prevCount + 1);
  };

  return (
    <div>
      <button onClick={increment}>Increment</button>
      <p>Count: {deferredCount}</p>
    </div>
  );
};

Enter fullscreen mode Exit fullscreen mode

No exemplo acima, o hook useDeferredValue é usado para atrasar a atualização do valor de estado count por 1 segundo.
Durante esse período, se o estado count for atualizado várias vezes, apenas a última atualização será refletida na renderização do componente.

O valor atrasado deferredCount é utilizado na renderização do componente, garantindo que apenas a atualização mais recente seja refletida no elemento <p>. Isso evita renderizações desnecessárias e melhora o desempenho do componente.

No caso de múltiplas atualizações do estado count dentro do período de atraso, apenas a atualização mais recente será visível após o término do período de atraso.

O useDeferredValue é especialmente útil quando você possui atualizações rápidas e frequentes em um valor de estado, mas deseja otimizar o desempenho do componente, evitando renderizações desnecessárias causadas por atualizações não críticas.

useTransition:

O hook useTransition é um hook introduzido no React 18 que permite adicionar transições suaves a alterações de estado.

Ele é útil para criar animações e efeitos visuais fluidos durante as transições de renderização.

Casos de Uso:

  1. Atualizações intensivas: Quando você tem atualizações de estado intensivas que podem causar interrupções visuais no seu aplicativo, o useTransition pode ser usado para suavizar essas transições. Ele permite que você aguarde um período curto antes de aplicar a atualização no estado, proporcionando uma experiência mais agradável aos usuários.
  2. Transições de carregamento: Se o seu aplicativo exibe elementos de carregamento ou indicadores de progresso, o useTransition pode ser usado para criar uma animação suave durante a transição entre o estado de carregamento e o estado concluído. Isso ajuda a evitar mudanças abruptas na interface do usuário e mantém os usuários engajados durante o processo de carregamento.
  3. Animações de entrada e saída: O useTransition é útil para criar animações de entrada e saída em elementos ou componentes. Por exemplo, você pode usar o hook para aplicar um efeito de desvanecimento ao exibir ou ocultar um modal, ou para animar a aparência de um elemento na tela quando um evento ocorre.

Exemplo:

import React, { useState, useTransition } from 'react';

const ComponentWithTransition = () => {
  const [showContent, setShowContent] = useState(false);
  const [startTransition, isPending] = useTransition({
    timeoutMs: 500, // Duration of the transition
  });

  const handleClick = () => {
    startTransition(() => {
      setShowContent(!showContent);
    });
  };

  return (
    <div>
      <button onClick={handleClick}>
        {showContent ? 'Hide Content' : 'Show Content'}
      </button>
      {isPending ? (
        <p>Loading...</p>
      ) : (
        showContent && <p>Content to be shown or hidden</p>
      )}
    </div>
  );
};

export default ComponentWithTransition;

Enter fullscreen mode Exit fullscreen mode

Quando o botão é clicado, a função handleClick é acionada. Dentro dela, chamamos startTransition e passamos uma função de retorno que atualiza o estado showContent.

Essa função de retorno será envolvida por uma transição, tornando a atualização de estado mais suave visualmente.

No render do componente, renderizamos condicionalmente o conteúdo com base em showContent. Se a transição estiver pendente (durante o período de transição), exibimos uma mensagem de carregamento. Caso contrário, mostramos o conteúdo apenas se showContent for true.

O hook useTransition nos permite adicionar um efeito de transição às atualizações de estado, proporcionando uma experiência visual mais suave para o usuário.

É especialmente útil ao lidar com mudanças intensas de estado ou ao adicionar animações durante as transições de IU.

Observação: O hook useTransition requer a versão 18 ou superior do React

useId:

O hook useId é usado para gerar um identificador único dentro de um componente no React. Ele é útil em casos em que você precisa atribuir um ID a um elemento de forma dinâmica, garantindo que o ID seja exclusivo em várias instâncias desse componente.

O caso de uso mais comum para o useId é quando você está renderizando uma lista de elementos e precisa atribuir um ID único a cada item da lista.

Dessa forma, cada item terá um identificador exclusivo, facilitando a referência e manipulação desses elementos.

Exemplo:

import React from 'react';
import { useId } from 'react-id-generator';

const ListaItens = ({ itens }) => {
  return (
    <ul>
      {itens.map((item) => (
        <Item key={useId()} texto={item} />
      ))}
    </ul>
  );
};

const Item = ({ texto }) => {
  const itemId = useId(); // Gera um ID único para cada item

  return <li id={itemId}>{texto}</li>;
};

const App = () => {
  const itens = ['Item 1', 'Item 2', 'Item 3'];

  return <ListaItens itens={itens} />;
};

export default App;

Enter fullscreen mode Exit fullscreen mode

Nesse exemplo, temos um componente ListaItens que recebe uma array de itens. Em seguida, iteramos sobre cada item usando o método map e, para cada item, usamos o useId() como o valor da propriedade key. Isso garante que cada item na lista tenha um ID exclusivo.

Dentro do componente Item, usamos novamente o useId() para gerar um ID único para cada item individualmente. Em seguida, atribuímos esse ID ao elemento <li> através da propriedade id.

Assim, cada item na lista terá um ID exclusivo gerado pelo useId(), permitindo identificar e manipular facilmente esses elementos de forma independente.

O hook useId é útil em situações em que você precisa gerar IDs únicos dinamicamente, evitando conflitos de ID em componentes renderizados repetidamente.

Conclusão:

Os Hooks adicionais do React fornecem aos desenvolvedores ainda mais flexibilidade e poder para criar componentes funcionais eficientes e reutilizáveis

Referencias

React Hooks
React.dev

Top comments (0)