Gerenciando estado remoto com React Query

Eduardo Rabelo
6 min readMay 5, 2021

React é uma das bibliotecas de front-end mais apreciadas pela comunidade de desenvolvedores. Junto com o React, os termos como DOM Virtual, Componentes Funcionais, Gestão de Estado e Componentes de Ordem-Superior (Higher-Order Components). Entre esses termos, a Gestão de Estado desempenha um papel vital.

O gerenciamento de estado é um dos principais fatores que precisam ser considerados antes de iniciar um projeto React. Os desenvolvedores usam padrões e bibliotecas famosas como Flux, Redux e Mobx para gerenciar o estado em React. No entanto, eles adicionam complexidade e código boilerplate ao seus aplicativos.

Neste artigo, vamos discutir como o React Query aborda o problema mencionado acima, criando um pequeno aplicativo pokemon e mergulhando em seus conceitos-chave.

Dica: Compartilhe seus componentes reutilizáveis entre projetos usando Bit (veja no GitHub). O Bit simplifica o compartilhamento, a documentação e a organização de componentes independentes de qualquer projeto.

Podemos usá-lo para maximizar a reutilização de código, colaboração em componentes independentes e criar aplicativos escaláveis.

O Bit suporta Node, TypeScript, React, Vue, Angular e muito mais.

O que é React Query?

React Query é uma das ferramentas de gerenciamento de estado que tem uma abordagem diferente do Flux, Redux e Mobx. Ele apresenta os principais conceitos de Estado-do-Cliente e Estado-do-Servidor. Isso torna o React Query uma das melhores bibliotecas para gerenciar estado, já que todos os outros padrões de gerenciamento de estado tratam apenas do estado do cliente e acham difícil lidar com o estado do servidor que precisa ser buscado, ouvido ou inscrito.

Além de lidar com o estado do servidor, ele funciona incrivelmente bem, sem precisar de configurações customizadas, e pode ser personalizado de acordo com o seu gosto conforme o crescimento do seu aplicativo.

Vamos ver isso na prática usando alguns exemplos.

Instalando o React Query

Em primeiro lugar, vamos instalar a React QUery dentro de um projeto React:

npm install react-query react-query-devtools axios --save

Ou:

yarn add react-query react-query-devtools axios

Configurando Ferramentas de Desenvolvimento

O React Query também tem suas próprias ferramentas de desenvolvimento, que nos ajudam a visualizar o funcionamento interno do React Query. Vamos configurar as ferramentas de desenvolvimento do React Query no arquivo App.js:

import { ReactQueryDevtools } from "react-query-devtools";
function App() {
return (
<>
{/* Os outros componentes da nossa aplicação */}
<ReactQueryDevtools initialIsOpen={false} />
</>
);
}

Quando configuramos as ferramentas de desenvolvimento do React Query, você pode ver o logotipo do React Query na parte inferior esquerda do seu aplicativo, assim:

O devtools nos ajuda a ver como o fluxo de dados acontece dentro do aplicativo, assim como Redux Devtools. Isso realmente ajuda a reduzir o tempo de depuração do aplicativo.

Assim como o GraphQL, o React Query também se baseia em conceitos básicos semelhantes, como

  • Query
  • Mutações
  • Invalidação de Query

Buscando Pokémons usando Query

Neste exemplo, vamos usar a PokéApi. Começaremos com useQuery, que recebe uma chave única e uma função responsável por buscar dados:

import React from "react";
import axios from "axios";
import { useQuery } from "react-query";
import Card from "./Card";
const fetchPokemons = async () => {
const { data } = await axios.get("https://pokeapi.co/api/v2/pokemon/?limit=50");
return data;
};
function Main() {
const { data, status } = useQuery("pokemons", fetchPokemons);
const PokemonCard = (pokemons) => {
return pokemons.results.map((pokemon) => {
return <Card key={pokemon.name} name={pokemon.name}></Card>;
});
};
return (
<div>
{status === "loading" && <div>Loading...</div>}
{status === "error" && <div>Error fetching pokemons</div>}
{status === "success" && <div>{PokemonCard(data)}</div>}
</div>
);
}
export default Main;

O código acima irá renderizar uma UI como abaixo:

Cache no React Query

Como você pode ver, useQuery retorna os dados e o status que podem ser usados ​​para exibir componentes de “Carregando…”, mensagens de erro e os dados reais. Por padrão, React Query só solicitará dados quando eles estiverem desatualizados ou antigos.

O React Query armazena os dados em cache para não renderizar os componentes, a menos que haja uma alteração. Também podemos usar alguma configuração especial com useQuery para atualizar os dados em segundo plano.

const {data, status} = useQuery ("pokemons", fetchPokemons, {staleTime: 5000, cacheTime: 10});

A configuração acima fará com que o React Query busque dados a cada 5 segundos em segundo plano. Também podemos definir um cacheTime e um retryTime que define o tempo que o navegador deve manter o cache e o número de tentativas em que ele deve buscar dados.

Redefinindo o Cache com Invalidação de Query

O React Query buscará dados assim que os dados / cache estiverem desatualizados. Isso acontece quando o staleTime padrão é passado. Você também pode invalidar o cache de maneira programática para que o React Query atualize os dados.

Para fazer isso, use queryCache. É uma instância utilitária que contém muitas funções que podem ser usadas para manipular ainda mais as Query e invalidar o cache.

queryCache.invalidateQueries("pokemons");

Variáveis no React Query

Também podemos passar variáveis ​​para a query. Para isso, precisamos transmiti-los como um array.

const { data, status } = useQuery(["pokemons",75], fetchPokemons);

O primeiro elemento será a chave e o resto dos elementos são variáveis. Para usar a variável, vamos fazer algumas modificações em nossa função fetchPokemons.

const fetchPokemons = async (key,limit) => {
const { data } = await axios.get(`https://pokeapi.co/api/v2/pokemon/?limit=${limit}`);
return data;
};

Brincando com Mutações

As mutações são normalmente usadas para criar / atualizar / excluir dados ou executar efeitos colaterais do lado do servidor. O React Query fornece o hook useMutation para realizar mutações. Vamos criar uma mutação para criar um pokémon:

import React from "react";
import { useQuery } from "react-query";
function Pokemon() {
const [name, setName] = useState("");
const [mutateCreate, { error, reset }] = useMutation(
(text) => axios.post("/api/data", { text }),
{
onSuccess: () => {
setName("");
},
}
);
return (
<div>
<form
onSubmit={(e) => {
e.preventDefault();
mutateCreate(name);
}}
>
{error && <h5 onClick={() => reset()}>{error}</h5>}
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<br />
<button type="submit">Create Pokemon</button>
</form>
</div>
);
}
export default Pokemon;

Neste exemplo, quando adicionamos um novo nome de Pokémon e clicamos no botão Criar Pokémon , ele fará a mutação e irá buscar os dados. Se a mutação falhar, o erro será exibido.

O erro e o estado dos dados podem ser eliminados usando a função reset, que reinicializará a mutação. A função onSuccess pode ser usada para limpar o estado da entrada ou do nome.

Uma mutação tem mais propriedades como onSuccess, isIdle , isLoading , isError , isSuccess. Eles podem ser usados ​​para lidar com erros e exibir informações relevantes para diferentes estados da mutação.

Conclusão

O React Query é uma das melhores maneiras de buscar, armazenar em cache e atualizar dados remotos. Precisamos apenas dizer à biblioteca onde você precisa buscar os dados, e ela tratará do cache, das atualizações em segundo plano e da atualização dos dados sem nenhum código ou configuração extra.

Ele também fornece alguns hooks e eventos para mutação e query para lidar com erros e outros estados dos efeitos colaterais, o que remove a necessidade de usar hooks como useState e useEffect e os substitui por algumas linhas com React Query.

Crédito

--

--