Reactのデータフェッチにはライブラリを使おう(Tanstack Query)

Reactでデータフェッチをするときには、ライブラリを使用した方が色々ありがたいお話です。

ライブラリを使用しない方法

ライブラリを使用しない従来の書き方になると、useStateとuseEffectを使用することになるでしょうか。

import { useEffect, useState } from "react"
import axios from "axios"

function ExampleWithoutuseQuery() {
  const [data, setData] = useState<any[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        // ローディング開始
        setIsLoading(true)
        const res = await axios.get("/api/todos");
        setData(res.data);
      } catch (err: any) {
        setError(err)
      } finally {
        // ローディング終了
        setIsLoading(false);
      }
    }
    // 初回マウント時にフェッチ関数を走らす
    fetchData();
  }, []);

  // ローディングUI
  if (isLoading) return <p>Loading...</p>
  // エラー時に表示するUI
  if (error) return <p>Error occurred</p>

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

このようにuseStateとuseEffectを使用して、自作で動きを管理する必要があります。
また、キャッシュや自動リフェッチが必要な場合も、自作しなければなりません。

useQueryを使用

import { useQuery } from "@tanstack/react-query"
import axios from "axios"

function Example() {
  const { data, isLoading, error } = useQuery({
    queryKey: ["todos"], // キャッシュのキー
    queryFn: async () => {
      const res = await axios.get("/api/todos")
      return res.data
    },
  })

  if (isLoading) return <p>Loading...</p>
  if (error) return <p>Error occurred</p>

  return (
    <ul>
      {data.map((todo: any) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  )
}

このようにuseQuery側でデータやローディング、エラーの管理をしてくれます。他にも色々。
キャッシュで無駄なリクエストを削減し、自動リフェッチで最新データを維持します。