O que é React-Query

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()

)

)

}

  1. Importamos a função useQuery.
  2. Criamos o componente funcional.
  3. 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:

  1. Crie uma aplicação React.

npx create-react-app my-project-with-query

  1. 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.

  1. 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.

  1. 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.

⚠️
As opiniões e comentários expressos neste artigo são de propriedade exclusiva de seu autor e não representam necessariamente o ponto de vista da Revelo.

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.