Explorando os Hooks Adicionais do React: Exemplos e Casos de Uso
Jhonata Vinicius Da Silva Araujo
Posted on May 23, 2023
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>
);
};
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>
);
};
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>;
};
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:
- 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.
- 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>
);
};
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:
- 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.
- 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>
);
};
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:
- 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.
- 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.
- 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>;
};
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:
- 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.
- 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.
- 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>
);
};
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:
- 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.
- 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.
- 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>
);
};
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:
- 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.
- 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.
- 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;
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;
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
Posted on May 23, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.