コンテンツへスキップ
ドキュメント
はじめに

はじめに

インストール

Reactプロジェクトディレクトリ内で、以下のコマンドを実行します。

pnpm add swr

クイックスタート

JSONデータを使用する通常のRESTful APIの場合、最初にネイティブのfetchのラッパーであるfetcher関数を生成する必要があります。

const fetcher = (...args) => fetch(...args).then(res => res.json())
💡

GraphQL APIやAxiosのようなライブラリを使用する場合は、独自のfetcher関数を生成できます。詳細な例についてはこちらを参照してください。

次に、useSWRをインポートし、任意の関数コンポーネント内で使用を開始できます。

import useSWR from 'swr'
 
function Profile () {
  const { data, error, isLoading } = useSWR('/api/user/123', fetcher)
 
  if (error) return <div>failed to load</div>
  if (isLoading) return <div>loading...</div>
 
  // render data
  return <div>hello {data.name}!</div>
}

通常、リクエストには「読み込み中」、「準備完了」、「エラー」の3つの状態があります。dataerrorisLoadingの値を使用してリクエストの現在の状態を判断し、対応するUIを返します。

再利用可能なコンポーネントの作成

ウェブアプリを構築する際には、UIの多くの場所でデータを再利用する必要がある場合があります。SWRの上に再利用可能なデータフックを作成することは非常に簡単です。

function useUser (id) {
  const { data, error, isLoading } = useSWR(`/api/user/${id}`, fetcher)
 
  return {
    user: data,
    isLoading,
    isError: error
  }
}

そして、それをコンポーネントで使用します。

function Avatar ({ id }) {
  const { user, isLoading, isError } = useUser(id)
 
  if (isLoading) return <Spinner />
  if (isError) return <Error />
  return <img src={user.avatar} />
}

このパターンを採用することで、**取得**データを命令型で処理する必要がなくなります。リクエストを開始し、読み込み状態を更新し、最終結果を返す必要はありません。代わりに、コードはより宣言的になります。コンポーネントで使用されるデータを指定するだけで済みます。

現実世界の例として、当社のウェブサイトではナビゲーションバーとコンテンツが表示されますが、どちらもuserに依存しています。

従来は、最上位レベルのコンポーネントでuseEffectを使用して一度データを取得し、プロップスを介して子コンポーネントに渡していました(現時点ではエラー状態は処理しません)。

// page component
 
function Page () {
  const [user, setUser] = useState(null)
 
  // fetch data
  useEffect(() => {
    fetch('/api/user')
      .then(res => res.json())
      .then(data => setUser(data))
  }, [])
 
  // global loading state
  if (!user) return <Spinner/>
 
  return <div>
    <Navbar user={user} />
    <Content user={user} />
  </div>
}
 
// child components
 
function Navbar ({ user }) {
  return <div>
    ...
    <Avatar user={user} />
  </div>
}
 
function Content ({ user }) {
  return <h1>Welcome back, {user.name}</h1>
}
 
function Avatar ({ user }) {
  return <img src={user.avatar} alt={user.name} />
}

通常、すべてのデータ取得を最上位レベルのコンポーネントに保持し、ツリーの深くに位置するすべてのコンポーネントにプロップスを追加する必要があります。ページにデータの依存関係がさらに追加されると、コードのメンテナンスが困難になります。

コンテキスト(新しいタブで開きます)を使用してプロップスの受け渡しを回避できますが、動的なコンテンツの問題が残ります。ページコンテンツ内のコンポーネントは動的になる可能性があり、最上位レベルのコンポーネントはその子コンポーネントでどのようなデータが必要になるかを認識できない可能性があります。

SWRはこの問題を完璧に解決します。作成したばかりのuseUserフックを使用すると、コードを次のようにリファクタリングできます。

// page component
 
function Page () {
  return <div>
    <Navbar />
    <Content />
  </div>
}
 
// child components
 
function Navbar () {
  return <div>
    ...
    <Avatar />
  </div>
}
 
function Content () {
  const { user, isLoading } = useUser()
  if (isLoading) return <Spinner />
  return <h1>Welcome back, {user.name}</h1>
}
 
function Avatar () {
  const { user, isLoading } = useUser()
  if (isLoading) return <Spinner />
  return <img src={user.avatar} alt={user.name} />
}

データは、データが必要なコンポーネントに**バインド**され、すべてのコンポーネントは互いに**独立**しています。すべての親コンポーネントは、データやデータの受け渡しについて何も知る必要はありません。単にレンダリングするだけです。コードははるかにシンプルになり、メンテナンスが容易になります。

最も素晴らしいのは、同じSWRキーを使用するため、APIへのリクエストは**1回**だけで済み、リクエストは自動的に**重複排除**、**キャッシュ**、**共有**されることです。

また、アプリケーションはユーザーのフォーカスやネットワークの再接続時にデータを再取得する機能も備えています!つまり、ユーザーのラップトップがスリープ状態から復帰したり、ブラウザのタブを切り替えた場合、データは自動的に更新されます。