Reactエンジニアの日常: fetchデータ保存でのstateトラブルとその解決策
はじめに
React を書き始めてからよく使うカスタムフックの中で useState と useEffect があります。
日々開発する中で、やってしまいがちな fetch したデータを useState で保存する方法。この中に含まれた不要な state の削除を目指します。
対象読者
- React の
useStateやuseEffectなどの基本的なカスタムフックを理解している - 初心者〜歴1年程度のフロントエンドエンジニア
fetch したデータを state に持たせる
useEffect で特定のエンドポイントからデータを取得し、必要なデータを state に入れる処理になります。
エンドポイントは呼び出されてから1秒後にダミーデータを返す実装となっております。
コードが抱える課題
- 3 回もレンダリングされる
- set 関数の変更が反映されない
3 回もレンダリングされる
この App コンポーネントは
- 初回レンダリング
- 1 つ目の
useEffect内で実行されるsetDataをトリガーとする再レンダリング - 2 つ目の
useEffect内で実行されるsetUsersをトリガーとする再レンダリング

3 回レンダリングが実行されます。1 つ目の useEffect はデータを取得するため外部との接続に必要です。一方で 2 つ目の useEffect や関連する useState は無くせるように感じられます。
また、App コンポーネントに子コンポーネントがあれば、その分レンダリングコストが増える実装です。
set 関数の変更が反映されない
先ほどのコードでは setUsers が公開されており、開発者はどこでも users の値を書き換えられます。以下のようなコードが JSX 内にあったとします。
...
<Button onClick={() => setUsers(usersLivedInUSA)}>
live in USA
</Button>
この機能の開発者は「アメリカに住んでいるユーザのみを表示する」という目的で用意したのでしょう。
しかし、ボタンをクリックしても初期のユーザが表示されるばかりです。
なぜでしょうか。順を追って見てみましょう。
- クリックによって再レンダリングがトリガー
-
usersとしてnewUsersがセットされた state が React からコンポーネントに渡される - useEffect の
fetchが再実行(fetch に react-query を使用) -
fetchの結果がusersにセットされる
アメリカ在住の users を表示したいのに、いつまでも最初の users が表示されます
改善
2 つ目の useEffect を削除し、users は data の有無で持たせるデータを変えるようにしました。
const users: User[] = data ? data : [];
この修正により、レンダリング回数は1回減り、必要のない state を減らすことができます。
まとめ
この記事では、React でよく使われる useState フックについて、不要な state を削除する方法について説明しました。
fetch したデータを state に保存する際に、不要な state を削除し、また不要なレンダリングを減らすため、余分な useEffect フックを削除しました。
これにより、コンポーネントのパフォーマンスを向上させることができます。
参考
Discussion