3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[日本語訳]SWR 入門

Last updated at Posted at 2021-01-04

追記: 2021年6月8日

SWR公式日本語訳ページが追加されたので、そちらをご覧ください

このページは Getting Started – SWRの日本語訳です
SWR日本語訳全体についてはSWR 日本語訳をご覧ください

インストール

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

yarn add swr

または

npm insatall swr

クイックスタート

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


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

💡 GraphQL APIまたはAxiosのようなライブラリを使用する場合は、独自のフェッチャー関数を作成できます。 その他の例については、こちらを確認してください。

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


import useSWR from 'swr'

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

  // データのレンダー
  return <div>hello {data.name}!</div>
}

通常、リクエストには3つの状態 "loading", "ready", または "error" が考えられます。 dataerror の値を使用して、リクエストの現在の状態を判断し、対応するUIを返すことができます。

再利用可能にする

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


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

  return {
    user: data,
    isLoading: !error && !data,
    isError: error
  }
}

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

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

このパターンを採用することで リクエストを開始し、ロード状態を更新して、最終結果を返す という命令的な方法でのデータのフェッチを忘れることができます。
代わりに、コンポーネントで使用されるデータを指定する という方法でコードはより宣言的です。

現実にあり得る例は、Webサイトのユーザーごとに異なる内容のナビゲーションバーとコンテンツが表示されている場合です。
スクリーンショット 2021-01-01 22.19.13.png

従来はuseEffectを使用して最上位コンポーネントでデータを一度フェッチし、propsを介して子コンポーネントに渡します(現時点ではエラー状態を処理しないことに注意してください)。


// ページコンポーネント
function Page () {
  const [user, setUser] = useState(null)

  // データのフェッチ
  useEffect(() => {
    fetch('/api/user')
      .then(res => res.json())
      .then(data => setUser(data))
  }, [])

  // グローバルの読み込み状態
  if (!user) return <Spinner/>

  return <div>
    <Navbar user={user} />
    <Content user={user} />
  </div>
}

// 子コンポーネント
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} />
}

通常、すべてのデータフェッチをトップレベルのコンポーネントに保持し、ツリーの奥深くにあるすべてのコンポーネントにpropsを追加する必要があります。 ページにデータ依存関係を追加すると、コードの保守が難しくなります。

Contextを使用してpropsを渡すことは避けられますが、動的コンテンツの問題があります。ページコンテンツ内のコンポーネントは動的である可能性があり、最上位コンポーネントはその子コンポーネントに必要なデータを認識していない可能性があります。

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


// ページコンポーネント
function Page () {
  return <div>
    <Navbar />
    <Content />
  </div>
}

// 子コンポーネント
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} />
}

これで、データはデータを必要とするコンポーネントにバインドされ、すべてのコンポーネントは互いに独立しています。 すべての親コンポーネントは、データやデータの受け渡しについて何も知る必要はありません。 これらはただレンダリングします。 コードははるかに単純になり、保守が容易になりました。

最も美しいのは、APIに送信されるリクエストが1つだけになることです。これは、APIが同じSWRキーを使用し、リクエストが重複排除され、キャッシュされ、自動的に共有されるためです。

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

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?