[日本語訳]SWR 入門

## 追記: 2021年6月8日
[SWR公式日本語訳ページ](https://swr.vercel.app/ja)が追加されたので、そちらをご覧ください

このページは [Getting Started – SWR](https://swr.vercel.app/getting-started)の日本語訳です
SWR日本語訳全体については[SWR 日本語訳](https://qiita.com/tk1024/items/1b8b4eb7cfaa92be6f1a)をご覧ください

# インストール
Reactプロジェクトディレクトリ内で、以下を実行します。

```
yarn add swr
```

または

```
npm insatall swr
```

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

```ts

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

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

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

```tsx

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" が考えられます。 `data` と `error` の値を使用して、リクエストの現在の状態を判断し、対応するUIを返すことができます。

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

```tsx

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

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

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

```tsx
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74405/b89c8eb3-0697-c811-fe67-875136939534.png)

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

```tsx

// ページコンポーネント
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を追加する必要があります。 ページにデータ依存関係を追加すると、コードの保守が難しくなります。

<a href="https://reactjs.org/docs/context.html">Context</a>を使用してpropsを渡すことは避けられますが、動的コンテンツの問題があります。ページコンテンツ内のコンポーネントは動的である可能性があり、最上位コンポーネントはその子コンポーネントに必要なデータを認識していない可能性があります。

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

```tsx

// ページコンポーネント
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キーを使用し、リクエストが**重複排除**され、**キャッシュ**され、自動的に**共有**されるためです。

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