Como Funciona a Busca de Dados no React?

Aplicativos React frequentemente dependem de APIs externas e bancos de dados para conteúdo dinâmico. Para acessar os dados dessas APIs e bancos de dados, você precisa usar algumas técnicas de obtenção de dados. Vamos dar uma olhada em como a obtenção de dados funciona no React e nas diferentes opções disponíveis para você para obter dados. React não é opinativo sobre como você busca seus dados, isso significa que, em um nível básico, você pode usar a Fetch API integrada, que todos os navegadores modernos suportam. Você também pode usar Axios e SWR. Axios é uma biblioteca de requisições HTTP baseada em promise construída sobre o objeto XMLHttpRequest e SWR é um hook do React para busca de dados criado pela equipe da Vercel. Vamos começar com um exemplo. Você primeiro precisa importar os hooks useState e useEffect:
import { useState, useEffect } from "react";
Então você precisará criar três variáveis de estado chamadas loading, data e error:
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
A variável loading irá monitorar se os dados ainda estão sendo buscados. A variável data representa os próprios dados e a variável error capturará quaisquer erros que possam ocorrer durante o processo de obtenção dos dados. Como a obtenção de dados é um efeito colateral, é melhor usar a Fetch API dentro de um hook useEffect. Aqui está um exemplo disso:
useEffect(() => {
  fetch("https://jsonplaceholder.typicode.com/posts")
    .then((res) => res.json())
    .then((data) => {
      setData(data);
      setLoading(false);
    })
    .catch((err) => {
      setError(err);
      setLoading(false);
    });
}, []);
Este useEffect busca os dados com a Fetch API e define todos os estados.  Você pode melhorar as coisas usando async/await em vez da sintaxe .then(). Isso significa que você precisa ter uma função separada dentro do useEffect porque não pode prefixar useEffect com a palavra-chave async:
useEffect(() => {
  const fetchData = async () => {
    try {
      const res = await fetch("https://jsonplaceholder.typicode.com/posts");
       
      if (!res.ok) {
        throw new Error("Network response was not ok");
      }

      const data = await res.json();
      setData(data);
    } catch (err) {
      setError(err);
    } finally {
      setLoading(false);
    }
  };

  fetchData();
}, []);
Você pode então usar todos esses estados para renderizar os dados da API. Aqui está o código completo:
import { useState, useEffect } from "react";

const FetchPosts = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const res = await fetch("https://jsonplaceholder.typicode.com/posts");
       
        if (!res.ok) {
          throw new Error("Network response was not ok");
        }

        const data = await res.json();
        setData(data);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  if (loading) {
    return <p>Loading...</p>;
  }

  if (error) {
    return <p>{error.message}</p>;
  }

  return (
    <ul>
      {data.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
};

export default FetchPosts;
Na interface, você veria Loading... na tela quando os dados estão sendo buscados e então os dados ou o erro seriam exibidos dependendo se a busca dos dados foi bem-sucedida. Lembre-se que também falamos sobre obtenção de dados com Axios e SWR. Vamos dar uma olhada em um exemplo usando Axios. Você precisará primeiro instalar o Axios pelo terminal assim:
npm i axios
Então você precisará importar o Axios assim:
import axios from "axios";
Então você pode usar as mesmas variáveis de estado de antes e buscar dados da API usando axios.get:
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
  const fetchData = async () => {
    try {
      const res = await axios.get(
        "https://jsonplaceholder.typicode.com/users"
      );
      setData(res.data);
    } catch (err) {
      setError(err);
    } finally {
      setLoading(false);
    }
  };

  fetchData();
}, []);
Você pode ter notado que não há a linha await res.json() neste exemplo. Isso acontece porque o Axios analisa JSON automaticamente, então não há necessidade disso. O último exemplo que vamos analisar é usar o hook useSWR para buscar dados. Assim como com Axios, você precisará instalar o SWR assim:
npm install swr
Então você precisará importar o hook useSWR para o arquivo assim:
import useSWR from "swr";
Em comparação com os exemplos anteriores, a sintaxe do SWR é muito mais curta. O que você precisa fazer é criar uma função fetcher e passá-la para o hook useSWR como seu segundo parâmetro (o endpoint é o primeiro parâmetro). Você também pode desestruturar tanto os estados de dados quanto de erro do hook useSWR, então você não precisa do hook useState. Aqui está a sintaxe:
const fetcher = (url) => fetch(url).then((res) => res.json());
const { data, error } = useSWR(endpoint, fetcher);
Observe que o nome "fetcher" aqui é apenas uma convenção, então você pode nomear a variável como quiser. Aqui está um componente buscando todos de JSON Placeholder API:
import useSWR from "swr";

const fetcher = (url) => fetch(url).then((res) => res.json());

const FetchTodos = () => {
  const { data, error } = useSWR(
    "https://jsonplaceholder.typicode.com/todos",
    fetcher
  );

  if (!data) {
    return <h2>Loading...</h2>;
  }
  if (error) {
    return <h2>Error: {error.message}</h2>;
  }

  return (
    <>
      <h2>Todos</h2>
      <div>
        {data.map((todo) => (
          <h3 key={todo.id}>{todo.title}</h3>
        ))}
      </div>
    </>
  );
};

export default FetchTodos;
Como você aprendeu em uma lição anterior sobre custom hooks, a busca de dados é uma lógica que você pode extrair para um custom hook. Então, se você está buscando dados em múltiplos componentes e páginas, o ideal é criar um useFetch hook. Aqui está um hook useFetch que usa SWR para busca de dados:
import useSWR from "swr";

const fetcher = (url) => fetch(url).then((res) => res.json());

const useFetch = (url) => {
  const { data, error } = useSWR(url, fetcher);

  return {
    data,
    loading: !data && !error,
    error,
  };
};

export default useFetch;
E aqui está como usar o hook useFetch para reescrever o primeiro exemplo que busca posts da API JSON Placeholder:
import useFetch from "./useFetch";

const FetchPosts = () => {
  const { data, loading, error } = useFetch(
    "https://jsonplaceholder.typicode.com/posts"
  );

  if (loading) {
    return <h2>Loading...</h2>;
  }

  if (error) {
    return <h2>{error.message}</h2>;
  }

  return (
    <>
      <h2>Posts</h2>
      <ul>
        {data.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </>
  );
};

export default FetchPosts;
Este módulo não possui perguntas. Marque como concluído.