3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

useEffect の罠—データ取得は useEffect じゃなくてもいい

Posted at

「データ取得は useEffect でやるもの」…本当にそうか?

フロントエンド開発の世界では、「これが王道だ」と信じられているベストプラクティスがいくつもある。
その中でも特に根強いのが、この思い込みだ。

「API からデータを取得するときは useEffect を使う」

確かに、useEffect を使えばコンポーネントのマウント時に API を叩いてデータを取得することができる。
これが「React でデータを取得する最も一般的な方法」だと言っていい。
だが、本当にそれが最適解なのか?

いや、そんなことはない。

Next.js を使うなら、useEffect でデータを取得するのはむしろ「悪手」になり得る。
ここでは、その理由と、より適した代替手段について考えてみよう。

1. useEffect によるデータ取得の問題点

典型的な useEffect を使ったデータ取得コードを見てみよう。

"use client";
import { useEffect, useState } from "react";

export default function Page() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch("/api/data")
      .then((res) => res.json())
      .then((data) => setData(data));
  }, []);

  if (!data) return <p>Loading...</p>;

  return <div>{data.message}</div>;
}

一見、問題ないように見える。
コンポーネントがマウントされたときに fetch を実行し、データが取得できたら setData で state を更新する。
よくある「React らしいコード」だ。

だが、ここに 3つの問題 がある。

問題①: クライアント側でしか動かない

このコードは useEffect の特性上、クライアントサイドでしか実行されない。
つまり、サーバーサイドレンダリング (SSR) ではデータがない状態でまず HTML を返し、その後クライアント側でデータを取得する。
結果として、ページ表示の速度が落ちる。

ページが表示されるまでの流れ
1. サーバーは空の HTML を返す → 画面には "Loading..." のみが表示される
2. クライアントが fetch で API を叩く → ここで初めてデータを取りに行く
3. データを受け取って state を更新 → ようやくデータが画面に表示される

これでは、ユーザーが待たされる時間が長くなる。

問題②: 「ちらつき (Flash of Empty Content)」が発生する

ページを開いたとき、一瞬 "Loading..." が表示され、その後データが表示される。
この 「一瞬何もない状態」 がユーザーの体験を悪化させる。

特に、テキストならまだしも、画像やレイアウトが変わる UI では、この「ちらつき」が不快に感じられることが多い。

問題③: クライアントの負荷が増える

useEffect を使うということは、データ取得の処理を クライアント側に押し付ける ということだ。
本来、これはサーバーで処理したほうが速いし、負荷も分散できる。

たとえば、Next.js の server components を使えば、データを 最初から HTML に埋め込んで返す ことができる。
そうすれば、クライアントが余計なリクエストをする必要もなく、初回レンダリングからデータがある状態になる。

2. useEffect を使わない Next.js のデータ取得方法

では、どうすればいいのか?
答えは「サーバーでデータを取得してしまうこと」 だ。

Next.js では、fetch をサーバーコンポーネント内で実行できる。
これを活用すれば、クライアントがデータを取りに行く前に、すでにサーバーがデータを埋め込んで返す ことができる。

改善版: サーバーコンポーネントでデータを取得

// app/page.tsx (App Router)

export default async function Page() {
  const res = await fetch("https://jsonplaceholder.typicode.com/posts/1");
  const data = await res.json();

  return <div>{data.title}</div>;
}

この方法なら、次のようなメリットがある。
• ページが表示された瞬間にデータがある
• クライアント側で fetch する必要がない
• SSR (サーバーサイドレンダリング) が効くので SEO も強い

特に、SEO を重視するサイトでは 「ページ表示の瞬間にデータがある」 ことが重要だ。
Google の検索エンジンは 「最初の HTML にデータが含まれているかどうか」 を評価基準にしているからだ。

3. それでも useEffect を使うべきケース

では、useEffect は完全に不要なのか? いや、そんなことはない。
クライアントサイドでの動的データ取得が必要な場合には、useEffect を使うのが正解だ。

useEffect を使うべき場面
• ユーザーの操作に応じてデータを取得する
• 例: 検索ボタンを押したとき
• リアルタイム更新が必要なデータ
• 例: WebSocket を使ったチャット
• クライアント固有のデータ (ローカルストレージ, クッキー)
• 例: ユーザーの設定情報の取得

これらのケースでは、useEffect の使用は適切だ。
だが、「ページロード時にデータを取得するだけ」なら、useEffect ではなく サーバーコンポーネント を使うべきだ。

結論

「データ取得は useEffect でやるもの」
—いや、そんなことはない。

Next.js を使うなら、サーバーコンポーネントや fetch を活用して、最初からデータを埋め込んで返す のがベストだ。
むやみに useEffect を使うと、ページの表示速度が遅くなり、UX も悪化する。

これからの Next.js でのデータ取得の鉄則

ページロード時のデータ取得 → サーバーでやる
ユーザー操作に応じたデータ取得 → クライアントでやる

「useEffect を使うのが当たり前」と思っているなら、一度立ち止まって考えてみてほしい。
それは本当に最適解なのか? いや、もっといい方法があるのではないか?

3
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?