React Hook - useAsync
O useAsync
é um React Hook personalizado que simplifica a lógica associada à execução de funções assíncronas em componentes React. Ele encapsula o gerenciamento de estados relacionados a operações assíncronas, proporcionando uma abordagem mais limpa e reutilizável para lidar com a assincronicidade no React.
Vamos explorar a implementação do useAsync
passo a passo:
1. Importação de Hooks
import { useCallback, useEffect, useState } from 'react';
O useAsync
utiliza useCallback
, useEffect
, e useState
do React.
2. Estado Interno do Hook
const [state, setState] = useState({
result: null,
error: null,
status: 'idle',
});
O estado interno do hook (state
) mantém informações sobre o resultado da operação assíncrona (result
), qualquer erro ocorrido (error
), e o status atual da operação (status
), que começa como ‘idle’.
3. Função run
e useCallback
const run = useCallback(() => {
setState({
result: null,
error: null,
status: 'pending',
});
return asyncFunction()
.then((response) => {
setState({
result: response,
error: null,
status: 'settled',
});
})
.catch((err) => {
setState({
result: null,
error: err,
status: 'error',
});
});
}, [asyncFunction]);
A função run
é responsável por iniciar a operação assíncrona. Ela atualiza o estado para refletir o início ('pending'
) e, após a conclusão ou erro, atualiza o estado para refletir o resultado ('settled'
) ou ('error'
), respectivamente. Utiliza-se useCallback
para garantir que a função não seja recriada em cada renderização, otimizando o desempenho.
4. Efeito para executar a função assíncrona
useEffect(() => {
if (shouldRun) {
run();
}
}, [run, shouldRun]);
Este efeito é acionado quando shouldRun
muda. Se for verdadeiro, chama a função run
, iniciando a execução da operação assíncrona.
5. Retorno do Hook
return [run, state.result, state.error, state.status];
O useAsync
retorna um array contendo a função run
para iniciar a operação, o resultado (result
), o erro (error
), e o status atual (status
). Esses valores podem ser utilizados no componente React que utiliza este hook.
6. Código
import { useCallback, useEffect, useState } from 'react';
const useAsync = (asyncFunction, shouldRun) => {
const [state, setState] = useState({
result: null,
error: null,
status: 'idle',
});
const run = useCallback(() => {
setState({
result: null,
error: null,
status: 'pending',
});
return asyncFunction()
.then((response) => {
setState({
result: response,
error: null,
status: 'settled',
});
})
.catch((err) => {
setState({
result: null,
error: err,
status: 'error',
});
});
}, [asyncFunction]);
useEffect(() => {
if (shouldRun) {
run();
}
}, [run, shouldRun]);
return [run, state.result, state.error, state.status];
};
Exemplo de uso
const fetchData = async () => {
const data = await fetch('https://jsonplaceholder.typicode.com/posts/');
const json = await data.json();
return json;
};
export const Home = () => {
const [reFetchData, result, error, status] = useAsync(fetchData, true);
function handleClick() {
reFetchData();
}
if (status === 'idle') {
return <pre>idle: Nothing running...</pre>;
}
if (status === 'pending') {
return <pre>pending: Loading...</pre>;
}
if (status === 'error') {
return <pre>error: {error.message}</pre>;
}
if (status === 'settled') {
return <pre onClick={handleClick}>settled: {JSON.stringify(result, null, 2)}</pre>;
}
return <pre>Something went wrong!</pre>;
};
O useAsync
é utilizado no componente Home
para gerenciar uma chamada assíncrona à função fetchData
. O resultado, erro e status são desestruturados para serem usados no componente.