追記: 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" が考えられます。 data
と error
の値を使用して、リクエストの現在の状態を判断し、対応する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サイトのユーザー
ごとに異なる内容のナビゲーションバーとコンテンツが表示されている場合です。
従来は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キーを使用し、リクエストが重複排除され、キャッシュされ、自動的に共有されるためです。
また、アプリケーションは、ユーザーフォーカスまたはネットワーク再接続でデータを再フェッチする機能を備えています! つまり、ユーザーのラップトップがスリープから復帰したり、ブラウザのタブを切り替えたりすると、データは自動的に更新されます。