【React.js】useSWRの使い方: useEffectとデータ取得における使いやすさとパフォーマンスを比較!
この記事では、Next.jsのVercel社が開発したuseSWRの使い方と、useEffectでデータ取得をする際の操作方法やパフォーマンスの違いを解説します!
3行で要約すると
useSWR
はReactのデータフェッチ用のフックで、キャッシングやリアルタイム更新などの機能が組み込まれている。- 自動的なデータ再取得やエラーハンドリングをシンプルなAPIで提供し、アプリケーションのレスポンス性を向上させる。
- 使用する際にはキーの一貫性、過度な再取得の回避、適切なエラーハンドリングに注意が必要。
「useSWR」の基本的な使い方
「useSWR」とは?
useSWR
は、React.jsのデータフェッチのためのフックです。SWRは「Stale While Revalidate」の略で、これは古い(stale)データを表示しながら新しいデータを検証(revalidate)するという方法を指します。このアプローチの最大の利点は、ユーザーが最新のデータを待たずに古いデータを見ることができる点です。そして、新しいデータが利用可能になった時、それを自動的に更新します。
具体的な使用例として、ユーザープロフィールをフェッチする場面を考えてみましょう。
import useSWR from 'swr'
// fetcher関数はAPIからデータを取得するための関数です。
// この例では、単にfetchを使っていますが、axiosなどの他のライブラリを使用することもできます。
const fetcher = url => fetch(url).then(res => res.json())
function Profile() {
const { data, error } = useSWR('/api/user', fetcher)
// エラーハンドリング
if (error) return <div>データの取得に失敗しました。</div>
// データがまだ取得されていない場合のハンドリング
if (!data) return <div>読み込み中...</div>
// データが取得された場合の表示
return <div>Hello {data.name}!</div>
}
このコードは、useSWR
を使用して/api/user
エンドポイントからデータを取得しています。取得したデータはdata
オブジェクトに格納され、エラーが発生した場合はerror
オブジェクトに格納されます。これにより、データの取得状況に応じて異なるUIを表示することができます。
「useSWR」の使用例5パターン
データリフレッシュのカスタマイズ
useSWR
は、データのリフレッシュ間隔や再試行の戦略をカスタマイズすることができます。たとえば、データを10秒ごとにリフレッシュしたい場合は、以下のようにrefreshInterval
オプションを使用します。
const { data } = useSWR('/api/user', fetcher, { refreshInterval: 10000 })
データの再試行
デフォルトでは、useSWR
は接続の問題やエラーが発生した場合に自動的にデータを再取得します。しかし、再試行の回数や間隔をカスタマイズすることもできます。以下は、3回再試行を試みる例です。
const { data } = useSWR('/api/user', fetcher, { revalidateOnReconnect: true, retry: 3 })
エラーのリトライ戦略のカスタマイズ
エラーが発生した場合のリトライ戦略もカスタマイズすることができます。例えば、特定のエラーコードの場合のみ再試行を行いたい場合、shouldRetryOnError
オプションを利用して実装できます。
const { data, error } = useSWR('/api/user', fetcher, {
shouldRetryOnError: false,
onError: (error, key) => {
if (error.status === 404) {
// 404エラーの場合のみ再試行
mutate(key);
}
}
})
複数のAPIエンドポイントからのデータ取得
useSWR
は複数のAPIエンドポイントからのデータを同時に取得する場合にも使えます。たとえば、ユーザーの情報とそのユーザーの投稿を別々のAPIエンドポイントから取得したい場合、以下のように実装できます。
const { data: user } = useSWR('/api/user', fetcher)
const { data: posts } = useSWR('/api/user/posts', fetcher)
if (!user || !posts) return <div>読み込み中...</div>
return (
<div>
<h1>{user.name}</h1>
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
)
ローカルの状態との組み合わせ
useSWR
はAPIからのデータフェッチだけでなく、ローカルの状態管理との組み合わせも可能です。例えば、ユーザーがフィルター条件を変更するたびにAPIからデータを再取得するシナリオを考えてみましょう。
const [filter, setFilter] = useState('all')
const { data: tasks } = useSWR(`/api/tasks?filter=${filter}`, fetcher)
return (
<div>
<select value={filter} onChange={e => setFilter(e.target.value)}>
<option value="all">すべて</option>
<option value="completed">完了</option>
<option value="pending">未完了</option>
</select>
<ul>
{tasks.map(task => (
<li key={task.id}>{task.title}</li>
))}
</ul>
</div>
)
この例では、フィルターの状態が変わるたびにAPIのエンドポイントのURLが変わり、useSWR
が新しいデータを自動的に取得します。
「useSWR」と「useEffect」
「useEffect」とは?
useEffect
はReactのHookで、コンポーネントのライフサイクル内で副作用(例えばデータの取得やDOMの操作)を実行するために使用されます。多くのReact開発者は、APIからデータを取得する際に、useEffect
とuseState
を組み合わせて使用してきました。
例:
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/user')
.then(response => response.json())
.then(data => setData(data));
}, []); // 空の依存配列は、このeffectを一度だけ実行することを意味します。
「useSWR」と「useEffect」の違い
useSWR
とuseEffect
をデータ取得のために使用する最大の違いは、useSWR
がデータフェッチのための多くの最適化とエラーハンドリングを提供する点です。
- リフレッシュ:
useSWR
はStale While Revalidate
戦略を採用しており、古いデータを表示しながら新しいデータを背後で取得します。 - エラーハンドリング:
useSWR
はエラーの取得と再試行の戦略を組み込んでいます。
コードの観点から比較すると:
// useEffectを使用したデータ取得
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/user')
.then(res => res.json())
.then(newData => setData(newData));
}, []);
// useSWRを使用したデータ取得
const { data } = useSWR('/api/user', fetcher);
さらにuseSWR
のパフォーマンスの利点として以下が挙げられます。
1. データキャッシング
useSWR
は内部でキャッシングを行います。これにより、一度取得したデータを再度取得する必要がなくなります。ユーザーがアプリケーション内を移動しても、同じデータを再取得するのではなくキャッシュから取得するので、レスポンスが速くなり、不必要なネットワークリクエストも削減されます。
2. バックグラウンドでのデータ更新
これは、キャッシュに保存されている古いデータ(stale data)を表示しながら、バックグラウンドで新しいデータを取得するというものです。これにより、ユーザーには最新のデータが速やかに表示され、アプリケーションの体感速度が向上します。
3. デデュプリケーション
useSWR
は、同じキーのリクエストが同時に複数行われることを防ぎます。これはデデュプリケーションと呼ばれる機能で、短時間内に同じデータへのリクエストが複数回行われた場合、実際のネットワークリクエストは1回だけ行われます。これにより、リソースの無駄な使用や不要なネットワークトラフィックが削減されます。
4. 並列リクエスト
複数のuseSWR
フックを使ってデータを取得する場合、これらのリクエストは並列に行われます。これにより、データ取得の全体の所要時間が短縮され、アプリケーションのレスポンスが向上します。
これらのパフォーマンスの利点は、開発者が特別な最適化を行うことなく、デフォルトでuseSWR
に組み込まれています。これにより、アプリケーションのパフォーマンスを簡単に向上させることができます。
「useSWR」を使用する際の注意点
使用上のメリットが多いuseSWR
ですが、適切に使用しなければ意図しない動作や問題が発生することがあります。以下に、useSWR
を使用する際の主な注意点と、それに関連するミスの例を示します。
注意点1: キーの一貫性
useSWR
のキーは、キャッシュの識別子として機能します。そのため、キーが一貫していないと、意図しないキャッシュの挙動やデータの取得ミスが発生する可能性があります。
例:
// これは問題がある例です
const { data: userData } = useSWR(user.id ? `/api/user/${user.id}` : null, fetcher);
このコードでは、user.id
が未定義の場合、null
をキーとしてuseSWR
が呼び出されます。このような動的なキーの使用は、データの取得ミスやキャッシュの問題を引き起こす可能性があります。
注意点2: リクエストの頻度
useSWR
は自動的にデータを再取得する機能がありますが、不要な再取得を避けるための設定を正しく行わないと、サーバーへの過度なリクエストが発生する可能性があります。
例:
// 頻繁に再取得される可能性がある例
const { data } = useSWR('/api/user', fetcher, { refreshInterval: 100 });
このコードでは、100msごとにデータの再取得が行われます。このような短い間隔での再取得は、多くの場合、サーバーへの負荷となります。
注意点3: エラーハンドリング
useSWR
はエラーハンドリングの機能を持っていますが、具体的なエラー処理を実装しなければ、ユーザーに適切なフィードバックが提供されない場合があります。
例:
const { data, error } = useSWR('/api/user', fetcher);
if (error) {
console.error("An error occurred:", error);
// このように、ログのみの処理ではユーザーは何が起きたのかわからない
}
このコードでは、エラーが発生した際にコンソールにログを出力するだけです。ユーザーには何も通知されませんので、何らかのUI上のフィードバックを提供するように実装することが重要です。
以上のように、useSWR
を使用する際はその特性と機能を理解した上で、適切な設定やエラーハンドリングを行うことが求められます。
「useSWR」の使い方まとめ
「useSWR」はReactアプリケーションでのデータフェッチにおいて、優れたパフォーマンスと使いやすさを提供するフックです。特に、自動的なデータ再取得やキャッシュ機能、エラーハンドリングなどの高度な機能をシンプルなAPIで使用できるのが魅力です。
まとめると、以下のような特徴と利点が挙げられます:
- キャッシング: 一度取得したデータはキャッシュされ、ページ間での遷移や再訪問時にも高速にデータを表示できます。
- リアルタイム更新:
refreshInterval
などのオプションを用いて、データの自動再取得を実現できます。 - エラーハンドリング: ネットワークエラーやAPIのエラーレスポンスを効果的にハンドリングできます。
- パフォーマンス: 他のフックやライブラリと比較しても、
useSWR
はアプリケーションのレスポンス性やユーザーエクスペリエンスを向上させます。
それでも、useSWR
を使う際には注意点もあります。特に、キーの一貫性の確保や、不要な再取得を避けるための設定、そして適切なエラーハンドリングは欠かせない要点となります。
この記事を通して、useSWR
の基本的な使い方やメリット、デメリット、使用上の注意点を理解できたと思います。Reactアプリケーションのデータ取得を効率的かつ効果的に行いたい場合、useSWR
の使用を検討してみてください。