Alura > Cursos de Front-end > Cursos de React > Conteúdos de React > Primeiras aulas do curso React Query: manipulando interações com mutations

React Query: manipulando interações com mutations

Conheça as mutations do React Query - Apresentação

Olá! Tudo bem? Meu nome é Patrícia Silva, sou instrutora da Escola de Front-end, e quero te dar boas-vindas a mais um curso na Alura.

Audiodescrição: Patrícia se descreve como uma mulher branca de cabelos cacheados pretos e olhos castanho-escuros. Ela usa óculos de armação preta arredondada, veste uma blusa rosa, e está sentada em um ambiente iluminado em azul e lilás, com alguns enfeites ao fundo.

O que vamos aprender?

Neste curso, trabalharemos com a aplicação Full Stack CodeConnect, na qual todas as requisições GET já estão implementadas, ou seja, os dados foram integrados ao back-end e são renderizados na tela.

No entanto, ainda precisamos implementar as funcionalidades de Thumbs Up e de adicionar e salvar comentários, persistindo-os tanto na página inicial, que lista todos os posts, quanto na página de detalhes de cada post específico.

A CodeConnect é uma rede social para pessoas desenvolvedoras. Nesse contexto, usaremos as mutations (mutações) do React Query, e o desafio será repleto de emoção, pois vamos trabalhar com técnicas avançadas, como a Optimistic Update, por exemplo.

Com essa técnica, manipulamos o cache para mostrar dados instantaneamente para as pessoas usuárias, melhorando a usabilidade e a experiência na nossa aplicação. Isso também melhora a performance, pois reduz o consumo de processamento do lado do servidor.

Além disso, vamos implementar testes unitários para as mutations, garantindo, assim, a qualidade e o comportamento dessas mutações.

Conclusão

Para acompanhar o conteúdo deste curso, você precisa conhecer React, JavaScript, async e await, além do básico sobre React Query.

Lembre-se de trazer muita força e energia, pois essa jornada será incrível!

Conheça as mutations do React Query - Criando o mutation para o thumbsUp

Após seguir os passos da atividade Preparando o ambiente, você terá acesso à página inicial, onde são listados todos os posts da aplicação CodeConnect.

Nosso desafio será incrementar o contador toda vez que a pessoa usuária clicar no botão Thumbs Up (ThumbsUpButton). Para isso, precisamos utilizar uma mutation (mutação).

Criando a mutation para o ThumbsUpButton

Usamos mutations para criar, atualizar ou deletar dados no servidor, ou se precisarmos realizar um side effect (efeito colateral), ou seja, mudar algo que não é necessariamente no servidor, mas que será uma modificação, a qual podemos exibir em tela.

Importando o hook useMutation

O componente dos posts é o CardPost. No VS Code, ele está localizado em "src > components > CardPost > index.jsx".

No topo do arquivo, na linha 1, vamos importar um hook especial chamado useMutation, que nos ajudará a realizar as mutações.

index.jsx (src > components > CardPost):

import { useMutation } from "@tanstack/react-query";

// código omitido

O ThumbsUpButton, para referência, está na linha 31 do mesmo arquivo.

// código omitido

<ThumbsUpButton disable={isFetching} />

// código omitido

Começaremos implementando a mutation antes disso, a partir da linha 13, e depois criaremos um evento no botão.

Criando a constante thumbsMutation

Na linha 13, criaremos uma const chamada thumbsMutation. Essa constante irá armazenar tudo que o useMutation() retornar, então ela será igual a useMutation().

// código omitido

export const CardPost = ({ post, highlight, rating, category, isFetching }) => {

  const thumbsMutation = useMutation({

  });

// código omitido

Criando o objeto de configuração

No escopo de useMutation(), precisamos passar um objeto de configuração. Esse objeto é muito parecido com o useQuery: passaremos uma propriedade chamada mutationFn, que será a função responsável por informar ao useMutation do React Query onde será performado o efeito colateral, isto é, onde ele deve realizar a criação, a atualização ou a remoção.

Estamos em uma aplicação Full Stack, e temos um endpoint que aceita o método POST para fazer a incrementação e informar qual ThumbsUpButton foi incrementado.

Na função mutationFn, basicamente, vamos receber o argumento, que são os dados do post (postData). Ela poderia ser declarada em outro arquivo, mas vamos implementar tudo no mesmo local.

// código omitido

const thumbsMutation = useMutation({
  mutationFn = (postData) => {

  }
});

// código omitido

Construindo a função mutationFn

No escopo da função, na linha 15, adicionaremos um return seguido de fetch(). Entre os parênteses, receberemos como argumento o endpoint http://localhost:3000/api/thumbs.

Após essa string, passaremos um objeto ({}), que será o objeto normal do fetch(): o método POST. Para isso, definimos method como "POST".

O headers, que passaremos na linha 17, é um objeto que contém o Content-Type do tipo application/json. Em seguida, vamos definir o body, que será igual a JSON.stringify() contendo o objeto que vamos passar para essa mutação, ou seja, o postData da linha 14.

// código omitido

const thumbsMutation = useMutation({
  mutationFn = (postData) => {
    return fetch("http://localhost:3000/api/thumbs", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(postData)
    });
  },
});

// código omitido

Criando um evento onClick para o botão

Nesse momento, temos o thumbsMutation implementado, fazendo um fetch() para o endpoint http://localhost:3000/api/thumbs, e passamos o body recebendo o objeto postData.

Agora, o componente ThumbsUpButton, que irá chamar a mutação, está na linha 41 do arquivo index.jsx. Na linha 40 logo acima, vamos adicionar um evento onClick no componente form.

Nesse evento, passaremos uma função (() =>) que irá chamar a mutation criada anteriormente. Entre os parênteses da função, vamos colocar um event, e no escopo, usaremos event.preventDefault() para evitar que a tela atualize, uma vez que o ThumbsUpButton está dentro de um formulário.

Para prevenir o comportamento natural, padrão do navegador, usamos a função preventDefault().

Por fim, na linha 43, adicionaremos thumbsMutation.mutate(). A função mutate() irá performar a mutação efetivamente, pois o thumbsMutation retorna várias outras propriedades.

Por exemplo: isError, isPending, entre outras.

No nosso caso, queremos realizar a mutação, então entre os parênteses de mutate(), passamos o objeto slug igual a post.slug, pois o endpoint espera isso para adicionar o Thumbs Up ao post.

// código omitido

<form
  onClick={(event) => {
    event.preventDefault();
    thumbsMutation.mutate({ slug: post.slug });
  }}
>
  <ThumbsUpButton disable={isFetching} />

// código omitido

Testando o código

Agora vamos acessar o navegador para testar se funcionou. Com a aplicação aberta, vamos teclar "F5" para atualizar e pressionar o botão Thumbs Up do primeiro post, por exemplo. A princípio, nada acontece na página, mas ao atualizar, aparece o número "1" abaixo do ícone.

Vamos o "Inspect" para analisar a aba "Network" e entender o que aconteceu. Quando clicamos no botão, é feita a requisição e a resposta é a seguinte:

{"message":"Thumbs up incremented successfully!"}

Conclusão

Concluímos que a ação foi salva no banco de dados, mas isso não é atualizado automaticamente na UI. Por que isso acontece? Explicaremos no próximo vídeo!

Conheça as mutations do React Query - Invalidando queries

O problema da tela não atualizar a quantidade de Thumbs Up após a mutation ser realizada com sucesso, ocorre porque ainda precisamos performar algumas atualizações.

Invalidando queries

Sabemos que as queries que buscam dados, ou seja, que realizam o método GET, são armazenadas em cache. Portanto, precisamos informar ao React Query quando ele precisa buscar novos dados. Em outras palavras, devemos dizer:

"Este dado não é mais válido, então, quando precisar dos dados novamente, você precisa acessar a rede para buscar os novos dados no servidor".

No momento, temos duas queries que trazem dados do método POST: uma é posts?page, ou seja, posts por página (posts?page=1, posts?page=2, …); e a outra é post?postId, post por ID (post?postId=11, post?postId=12, …). Precisaremos invalidar essas queries.

Importando o hook useQueryClient

De volta ao VS Code, começaremos importando um hook chamado useQueryClient. Faremos isso na linha 1 do arquivo index.jsx da pasta "src > components > CardPost".

index.jsx (src > components > CardPost):

import { useMutation, useQueryClient } from "@tanstack/react-query";

// código omitido

Feito isso, precisaremos utilizar essa instância, então adicionaremos na linha 12, logo após a declaração de CardPost, uma const queryClient igual a useQueryClient().

// código omitido

export const CardPost = ({ post, highlight, rating, category, isFetching }) => {
  const queryClient = useQueryClient();

// código omitido

Utilizando o callback onSuccess

Em breve, aplicaremos a constante queryClient em uma invalidação de queries, mas antes precisamos utilizar alguns callbacks que existem no useMutation().

Entre os callbacks do useMutation, temos, por exemplo, o onSuccess. Toda vez que a mutation for finalizada com sucesso, esse callback executará a função que vamos adicionar.

O callback onSuccess só irá correr quando a mutation for finalizada com sucesso. Afinal, não adianta invalidar dados se houve erro. Porém, existem outros callbacks que iremos abordar no decorrer do curso.

Dito isso, na linha 22, digitaremos onSuccess: () => {}.

// código omitido

const thumbsMutation = useMutation({
  mutationFn: (postData) => {
    return fetch("http://localhost:3000/api/thumbs", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(postData),
    });
  },
  onSuccess: () => {

  }
});

// código omitido

Invalidando as queries

No escopo da função, faremos a invalidação das queries que mencionamos anteriormente, para quando a mutation ocorrer com sucesso, invalidarmos os dados. Dessa forma, assim que alguma pessoa usuária acessar essa tela, a query será chamada novamente.

Na linha 23, usaremos o método queryClient.invalidateQueries() para definir a invalidação da query ["post", post.slug].

// código omitido

onSuccess: () => {
  queryClient.invalidateQueries(["post", post.slug]);
}

// código omitido

Ainda queremos invalidar uma segunda query: na linha 24, adicionaremos queryClient.invalidateQueries(["posts", currentPage]).

// código omitido

onSuccess: () => {
  queryClient.invalidateQueries(["post", post.slug]);
  queryClient.invalidateQueries(["posts", currentPage]);
}

// código omitido

Feito isso, precisamos passar o componente currentPage para a função de CardPost, na linha 11.

// código omitido

export const CardPost = ({
  post,
  highlight,
  rating,
  category,
  isFetching,
  currentPage,
}) => {
  const queryClient = useQueryClient();

// código omitido

Importando o componente currentPage

Até o momento, ainda não importamos o componente currentPage. Quem usa o CardPost é a página inicial, do arquivo "src > app > page.js".

Na linha 37, temos o currentPage na função fetchPosts(), e queremos passá-lo para o CardPost, a partir da linha 67. Portanto, na linha 73, vamos definir o currentPage igual a {currentPage}.

page.js (src > app):

// código omitido

<CardPost
  key={post.id}
  post={post}
  rating={ratingsAndCartegoriesMap?.[post.id]?.rating}
  category={ratingsAndCartegoriesMap?.[post.id]?.category}
  isFetching={isFetching}
  currentPage={currentPage}
/>

// código omitido

Testando o código

Com o navegador aberto, vamos testar se as queries serão invalidadas e se a UI será atualizada. Após atualizar a página, apertaremos o botão Thumbs Up novamente. Agora ele incrementa perfeitamente.

Perceba que toda vez que clicamos, ele vai até a rede, primeiro para performar a mutation, e depois para invalidar as queries.

Isso não significa que, para invalidar as queries, ele vai para a rede. Após invalidar, como já estamos na página, o dado precisa ser requisitado novamente e ele vai para a rede. Essa é a ordem.

Sobre o curso React Query: manipulando interações com mutations

O curso React Query: manipulando interações com mutations possui 138 minutos de vídeos, em um total de 39 atividades. Gostou? Conheça nossos outros cursos de React em Front-end, ou leia nossos artigos de Front-end.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda React acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas