メインコンテンツまでスキップ

データ読み込み

TanStack Query continues its growth trajectory, both in terms of usage and positivity. The interest graph in particular reveals that –along with tRPC– it's pretty much the only data loading library that is still intriguing respondents today!

(訳) TanStack Queryは、使用率と好感度の両面で成長の軌跡をたどり続けています。特に「関心度グラフ」を見ると、tRPCと並んで、現在も回答者の関心を惹きつけているほぼ唯一のデータローディングライブラリであることが明らかになっています!

https://2024.stateofreact.com/en-US/libraries/data-loading/ より引用

Fetch API による基本的なデータ取得

React でデータを取得する最も基本的な方法は、Fetch API と useEffect を組み合わせることです。

Fetch API のサンプル

JSONPlaceholder という無料の API を使って、投稿一覧を取得するサンプルです。

import { useState, useEffect } from 'react';

interface Post {
id: number;
title: string;
body: string;
}

export default function App() {
const [posts, setPosts] = useState<Post[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);

useEffect(() => {
  async function fetchPosts() {
    try {
      setLoading(true);
      setError(null);

      const response = await fetch(
        'https://jsonplaceholder.typicode.com/posts?_limit=5'
      );

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      const data = await response.json();
      setPosts(data);
    } catch (err) {
      setError(err instanceof Error ? err.message : '不明なエラー');
    } finally {
      setLoading(false);
    }
  }

  fetchPosts();
}, []);

if (loading) {
  return (
    <div style={{ padding: '20px', textAlign: 'center' }}>
      <p>読み込み中...</p>
    </div>
  );
}

if (error) {
  return (
    <div style={{ padding: '20px' }}>
      <div
        style={{
          padding: '16px',
          backgroundColor: '#f8d7da',
          color: '#721c24',
          borderRadius: '4px',
          border: '1px solid #f5c6cb'
        }}
      >
        エラー: {error}
      </div>
    </div>
  );
}

return (
  <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
    <h1>投稿一覧</h1>
    <p style={{ color: '#666', marginBottom: '20px' }}>
      Fetch API でデータを取得
    </p>

    <div style={{ display: 'grid', gap: '16px' }}>
      {posts.map((post) => (
        <article
          key={post.id}
          style={{
            padding: '16px',
            backgroundColor: '#f8f9fa',
            borderRadius: '8px',
            border: '1px solid #dee2e6'
          }}
        >
          <h3 style={{ margin: '0 0 8px 0', color: '#007bff' }}>
            {post.title}
          </h3>
          <p style={{ margin: 0, color: '#555', lineHeight: '1.6' }}>
            {post.body}
          </p>
        </article>
      ))}
    </div>
  </div>
);
}

TanStack Query を使ったデータ取得

TanStack Query は、データ取得、キャッシング、同期、更新を簡単に行えるライブラリーです。

TanStack Query のサンプル

同じデータを TanStack Query を使って取得する例です。

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import PostList from './PostList';

const queryClient = new QueryClient({
defaultOptions: {
  queries: {
    refetchOnWindowFocus: false,
  },
},
});

export default function App() {
return (
  <QueryClientProvider client={queryClient}>
    <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
      <h1>投稿一覧</h1>
      <p style={{ color: '#666', marginBottom: '20px' }}>
        TanStack Query でデータを取得
      </p>
      <PostList />
    </div>
  </QueryClientProvider>
);
}

TanStack Query の高度な機能

キャッシングとバックグラウンド更新のデモ

TanStack Query の強力なキャッシング機能を体験できるサンプルです。

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useState } from 'react';
import UserList from './UserList';

const queryClient = new QueryClient({
defaultOptions: {
  queries: {
    staleTime: 10000, // 10秒間はキャッシュを使用
    refetchOnWindowFocus: false,
  },
},
});

export default function App() {
const [showUsers, setShowUsers] = useState(true);

return (
  <QueryClientProvider client={queryClient}>
    <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
      <h1>TanStack Query のキャッシング</h1>

      <div style={{ marginBottom: '20px' }}>
        <button
          onClick={() => setShowUsers(!showUsers)}
          style={{
            padding: '10px 20px',
            backgroundColor: showUsers ? '#dc3545' : '#28a745',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          {showUsers ? 'ユーザーリストを隠す' : 'ユーザーリストを表示'}
        </button>
        <p style={{ marginTop: '8px', fontSize: '14px', color: '#666' }}>
          リストを隠して再表示すると、キャッシュからデータが即座に表示されます
        </p>
      </div>

      {showUsers && <UserList />}
    </div>
  </QueryClientProvider>
);
}

TanStack Query の主な機能

  • 自動キャッシング: 一度取得したデータは自動的にキャッシュされ、再利用される
  • バックグラウンド更新: 古いデータを表示しながら、バックグラウンドで新しいデータを取得
  • リクエストの重複排除: 同じクエリキーのリクエストは自動的に統合される
  • 自動リトライ: エラー時に自動的にリトライする
  • データの無効化: 特定のデータを無効化して再取得させることができる
  • 楽観的更新: サーバーレスポンスを待たずに UI を更新できる

SWR を使ったデータ取得

SWR は、Vercel が開発したデータフェッチングライブラリーです。名前は HTTP キャッシュ戦略の "stale-while-revalidate" に由来しています。

SWR のサンプル

TanStack Query と似た機能を持ちますが、よりシンプルな API が特徴です。

import { SWRConfig } from 'swr';
import PostList from './PostList';

export default function App() {
return (
  <SWRConfig
    value={{
      revalidateOnFocus: false,
      dedupingInterval: 10000,
    }}
  >
    <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
      <h1>投稿一覧</h1>
      <p style={{ color: '#666', marginBottom: '20px' }}>
        SWR でデータを取得
      </p>
      <PostList />
    </div>
  </SWRConfig>
);
}

SWR の主な機能

  • シンプルな API: useSWR フック一つで簡単にデータ取得
  • 自動再検証: フォーカス時、再接続時、定期的にデータを自動更新
  • キャッシング: 同じキーのリクエストは自動的にキャッシュされる
  • 軽量: 小さなバンドルサイズで高速
  • TypeScript サポート: 型安全なデータフェッチング
  • 楽観的更新: mutate 関数でローカルデータを即座に更新

まとめ