O que é React-Query
React Query é uma biblioteca usada para trabalhar com requisições assíncronas, trazendo o conceito de estado do servidor para o desenvolvimento React, tem uma configuração inicial simples e sem necessidade de customização.
De maneira breve, o react-query é uma biblioteca que surgiu com o objetivo de facilitar a maneira como lidamos com fetch. Normalmente, no React, quando queremos realizar um fetch, não conseguimos fazê-lo de maneira direta e simples e se torna necessário criar uma estrutura para sincronizar, pegar erros e atualizar o componente, o que, muitas vezes, implica no uso de React Hooks e bibliotecas para o gerenciamento de estado. Outras bibliotecas que trabalham com gerenciamento de estado acabam deixando a aplicação mais complexa e com código boilerplate. Com esse problema surgiu a biblioteca react-query, que torna as atividades de fetch, catch e async mais simples.
Antes, sem o React Query, o componente seria assim:
//Importamos o react e os ganchos:
import React, { useState, useEffect } from 'react;
//Criamos um component funcional:
function MyComponent() {
//Estado remoto que vai guardar a data depois do fetch:
const [ data, setData ] = this.useState({});
//Estado que ira guardar o status da requisição:
const [ status, setStatus ] this.useState('');
//Estado que vai guardar a mensagem de erro:
const [ errMsg, setErrMsg ] this.useState('');
//O useEffect serve para controlar o ciclo de vida e pegar a data na criação do componente:
useEffect(() => {
//Criamos a função que vai fazer o fetch.
const fetchData = async () {
setStatus("loading");
fetch(URL)
.then(result => result.json())
.then(data => {
//Após pegar a data decodificada guardamos ela nos estados remotos:
setData(data)
setStatus("success");)
}
.catch(error => {
setStatus("failed");
setErrorMsg(e.msg);
});
}
}
fetchData();
}, []);
};
- Importamos os ganchos e o React.
- Criamos o componente funcional.
- Usamos useEffect para fazer a requisição no começo do ciclo de vida do componente.
- Criamos os estados remotos que irão guardar o conteúdo do fetch, o status e a mensagem de erro, caso exista.
- Criamos uma função assíncrona que é responsável por decodificar, guardar no estado global e pegar erros.
- Chamamos a função criada.
Claramente usamos muitas linhas de código, foram usados muitos recursos e temos pouco controle da requisição.
Quando usamos o React Query o código fica dessa maneira:
// Importamos o gancho para acessar as funcionalidades
import { useQuery } from ‘react-query’;
function Example() {
// Nomeamos o repositorio do servidor e acessamos as propriedades
const { isLoading, error, data } = useQuery('repoData', () =>
fetch('https://api.github.com/repos/tannerlinsley/react-query').then(res =>
res.json()
)
)
}
- Importamos a função useQuery.
- Criamos o componente funcional.
- Desconstruímos o objeto retornado do useQuery e passamos os parâmetros para a função.
Como podemos ver, foi usado bem menos código e a sintaxe é bem mais simples, possibilitando também colocar listeners nas requisições para disparar ações, ter controle do cache, entre diversas outras funcionalidades.
Estado do Servidor
Antes de começarmos, é importante entender o conceito de Server State. Um dos maiores diferenciais do React Query é que ele estabelece que a maneira antiga de se tratar os dados estava errada. Devemos tratar o estado do servidor separadamente, tendo assim, o “Estado da aplicação” e o “Estado do servidor”. Da maneira usual, não podemos garantir que o usuário está vendo o estado atualizado, fazendo mais sentido tratar de forma separada, tornando possível, coisas como, pegar os dados do servidor continuamente.
Primeiros passos no React-Query
Primeiramente vamos começar o React Query por uma abordagem mais simples:
- Crie uma aplicação React.
npx create-react-app my-project-with-query
- Entre no diretório e instale as dependências do React Query.
cd my-project-with-query
npm install react-query react-query-devtools axios --save
* Caso de erro com o react-query-devtools mude a versão do react-query no package.json para 3.12.6 e rode o comando npm install.
- Para o correto funcionamento da biblioteca temos que criar um Provider React Query para podermos saber como outros componentes dentro do provider estão tratando os dados do estado do servidor.
src/index.js :
import React from 'react';
import ReactDOM from 'react-dom/client';
// Importamos os componentes necessários para o provider
import { QueryClient, QueryClientProvider } from 'react-query';
import { ReactQueryDevtools } from 'react-query/devtools';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// Criamos o cliente para ter acesso ao cache
const queryClient = new QueryClient();
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
// Envolvemos nossos componentes no provider e passamos a prop cliente que recebe O queryClient
<QueryClientProvider client={queryClient}>
<App />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
No código a cima, primeiro importamos QueryClientProvider. Ele é usado para criar o React Query Provider. Depois, importamos o QueryClient, responsável por criar o cliente do React Query e, por ultimo, envolvemos nossos componentes com o QueryClientProvider.
É recomendado usar o React Query Devtools para se ter uma interface visual da biblioteca, para usá-lo, importamos o componente e colocamos como o ultimo elemento no React Query Provider.
- Agora que temos nosso provider podemos aplicar a mesma lógica pra todos os componentes inseridos nesse contexto. Vamos usar de exemplo o arquivo App.js que vem por padrão na pasta src.
src/App.js :
// Importamos o gancho
import { useQuery } from 'react-query';
function App() {
// Descontruimos o useQuery e passamos os parametros para a função
const { isLoading, error, data } = useQuery('repoData', () =>
// O primeiro parametro nomeia a requisição e o segundo éresponsavel pelo fetch
fetch('https://api.github.com/repos/tannerlinsley/react-query').then(res =>
res.json()
)
)
// Caso esteja carregando renderizamos isso na tela
if (isLoading) return 'Loading...'
// Caso tenha dado um erro na requisição renderizamos isso na tela
if (error) return 'Tivemos um erro' + error.message
// Caso de tudo certo renderizamos o conteudo da requisição a data.
return (
<div>
<h1>{data.name}</h1>
<p>{data.description}</p>
<strong>:eyes: {data.subscribers_count}</strong>{' '}
<strong>:sparkles: {data.stargazers_count}</strong>{' '}
<strong>:fork_and_knife: {data.forks_count}</strong>
</div>
)
};
export default App;
No React Query, temos as famosas queries que, resumidamente, são usadas para obter dados do servidor e alterar algumas configurações de fetch.
Analisando o código a cima, podemos ver que desconstruímos o objeto retornado da função useQuery para usar algumas informações:
- data: Para “pegar” as informações.
- isLoading: Para Verificar o carregamento.
- erros: Para Verificar a existência de erros.
É Importante lembrar que existem muitas outras queries, porém, começaremos somente com essas.
Na função useQuery que importamos, podemos passar alguns parâmetros:
Query Key
Um identificador para a requisição. Essa Query Key serve para que o React Query possa fazer o controle da requisição de forma única e não se confundir fazendo fetchs duplicados. Por exemplo, ao ter dois componentes usando a mesma Query Key, garantimos que só sera feito um fetch.
Função fetch
No segundo parâmetro passamos a função que é responsável pelo fetch, essa função retornara uma Promise e o useQuery enviara esse resultado para a constante “data”.
Com isso já conseguimos usar o React Query, porém, ainda tem muito mais a se aproveitar da biblioteca.
Configurar Queries na função useQuery
Além das queries usadas até agora podemos passar um objeto como parâmetro do useQuery e nesse objeto, passar algumas propriedades que funcionarão como uma espécie de configuração do fetch. Segue o exemplo a seguir:
src/App.js :
// Importamos o gancho
import { useQuery } from 'react-query';
function App() {
// Descontruimos o useQuery e passamos os parametros para a função
const { isLoading, error, data } = useQuery('repoData', () =>
// O primeiro parametro nomeia a requisição e o segundo éresponsavel pelo fetch
fetch('https://api.github.com/repos/tannerlinsley/react-query').then(res =>
res.json()
) ,
{
refetchOnWindowFocus: false,
retry: 6,
refetchInterval: 1000,
onSuccess: (data) => {
console.log(data);
},
onError: (error) => {
console.log(error)
},
}
)
// Caso esteja carregando renderizamos isso na tela
if (isLoading) return 'Loading...'
// Caso tenha dado um erro na requisição renderizamos isso na tela
if (error) return 'Tivemos um erro' + error.message
// Caso de tudo certo renderizamos o conteudo da requisição a data.
return (
<div>
<h1>{data.name}</h1>
<p>{data.description}</p>
<strong>:eyes: {data.subscribers_count}</strong>{' '}
<strong>:sparkles: {data.stargazers_count}</strong>{' '}
<strong>:fork_and_knife: {data.forks_count}</strong>
</div>
)
};
export default App;
Agora adicionamos algumas queries ao objeto que vão mudar o funcionamento padrão do fetch, no nosso exemplo temos:
refetchOnWindowFocus
Essa propriedade vem true como padrão e é responsável por fazer o fetch sempre que o usuário sai e volta para a tela de navegação. Sendo assim, muito útil para atualizar os dados somente quando o usuário está efetivamente usando o app.
retry
Serve para tentar o fetch mais de uma vez, pode ser usado para evitar problemas causados por erros de conexão. Ele vem por padrão como 3, porém, também pode receber valores boleanos como true e false. Quando true ele tenta infinitamente até conseguir, quando false ele não tenta mais que uma vez. No nosso exemplo, o retry foi usado para garantir que ele tente o fetch, por, no máximo, 6 vezes antes de retornar o erro.
refetchInterval
Chamado também de polling, o refetchInterval é responsável por fazer o fetch de maneira periódica. No nosso exemplo, estamos tentando o fazer fetch a cada 1 segundo. Essa propriedade pode ser usada quando precisamos dos dados sendo atualizados constantemente, como, por exemplo, um fetch que retorna o horário atual.
onSuccess
Nessa propriedade passamos uma função que será chamada quando a requisição tiver sido feita com sucesso, no nosso caso, chamamos uma função anonima somente para fazer um console.log da constante “data”.
onError
É uma propriedade que passamos uma função que sera chamada quando ocorre um erro na requisição, no exemplo usamos para dar um console.log da constante “data” também.
Conclusão
Sem o React Query, para garantir que o conteúdo do fetch será renderizado assim que o usuário entrar na página, precisamos usar o ciclo de vida dos componentes e guardar os dados no estado local. Já com o Query, essa ação é feita automaticamente, removendo a necessidade de trabalhar com o ciclo de vida dos componentes, e também, removendo a necessidade de usar o estado remoto, o que melhora o desempenho e a complexidade diminui bastante.
Desenvolver aplicações com ele tornou muito mais fácil trabalhar com assincronicidade. Mesmo quando a aplicação é maior, a sintaxe continua curta e a experiência do usuário fica bem mais fluída. React Query foi a melhor biblioteca para lidar com dados envolvendo o servidor que encontrei e usarei muito em meus futuros projetos.
A Revelo Content Network acolhe todas as raças, etnias, nacionalidades, credos, gêneros, orientações, pontos de vista e ideologias, desde que promovam diversidade, equidade, inclusão e crescimento na carreira dos profissionais de tecnologia.