Next.jsで学ぶReact講座(完全初心者向け・30日) | 第4章:実用的React – データ取得(fetch)

React Next.js
スポンサーリンク

APIとは何か

「データください」をお願いするための窓口

React / Next.js で「データを画面に表示したい」とき、
どこかからデータを「取ってくる」必要があります。

そのときに話に出てくるのが API(エーピーアイ)です。
ここでは、Web の世界でよく言う「Web API」のイメージで話します。

ざっくり言うと、API は

「このURLにこういうルールでアクセスしてくれたら、
決まった形でデータを返しますよ」

という約束事(窓口)です。

例えば、こんな API があるとします。

  • https://example.com/api/users にアクセスすると
    ユーザー一覧のデータを JSON で返す
  • https://example.com/api/posts にアクセスすると
    記事の一覧を返す

Next.js / React からすると、

「この URL に対して、データください」とリクエストを送り
返ってきた JSON を state に入れて
それを JSX で画面に表示する

という流れになります。


fetchの基本

fetch は「URLからデータを取ってくるための関数」

ブラウザには、fetch という標準の関数があります。
これを使うと、指定した URL に HTTP リクエストを送り、レスポンス(返答)を受け取ることができます。

超シンプルな例から。

fetch("https://example.com/api/users")
  .then((response) => {
    return response.json();
  })
  .then((data) => {
    console.log(data);
  });
TSX

ここで起きていることを順番に見ると、

1つ目の then で、HTTP レスポンスオブジェクトを受け取る
response.json() で「JSON を JavaScript のオブジェクトに変換してください」とお願いする
2つ目の then で、変換されたデータ(オブジェクトや配列)が data に入る
console.log(data) で中身を確認できる

最近は async / await を使う書き方のほうが読みやすいので、
React コンポーネントの中ではだいたいこちらを使います。

async function loadUsers() {
  const response = await fetch("https://example.com/api/users");
  const data = await response.json();
  console.log(data);
}
TSX

「fetch でレスポンスを取ってくる → response.json() で JSON を JS に変換する」
この二段階が基本形です。


JSONの扱い

JSON は「JavaScript 風のデータの書き方」

JSON(ジェイソン)は、データを表現するためのフォーマットです。
見た目はほぼ JavaScript のオブジェクト/配列と同じです。

例えば、こんな JSON があります。

{
  "id": 1,
  "name": "太郎",
  "skills": ["JavaScript", "React"],
  "age": 25
}

これを response.json() で変換すると、JavaScript ではこういうオブジェクトになります。

const user = {
  id: 1,
  name: "太郎",
  skills: ["JavaScript", "React"],
  age: 25,
};
TSX

つまり、

  • fetch が返すのは「文字列としての JSON」
  • .json() を呼ぶと「JavaScript でそのまま使えるオブジェクトや配列」に変換される

というイメージです。

React 的には、この変換済みのデータを useState に入れて、
map などで画面に表示していくことになります。


画面に表示するまでの一連の流れ

例:ダミーAPIから記事一覧を取得して表示する

実際に、fetchuseEffectuseState を組み合わせて
「APIからデータを取ってきて画面に表示するコンポーネント」を作ってみます。

ここでは、練習用に有名なダミーAPI https://jsonplaceholder.typicode.com/posts を例にします。
(実際には自分のAPIや Next.js の API Routes でも同じ発想で書けます)

"use client";

import { useEffect, useState } from "react";

type Post = {
  id: number;
  title: string;
  body: string;
};

export default function PostsPage() {
  const [posts, setPosts] = useState<Post[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    async function fetchPosts() {
      try {
        setIsLoading(true);
        setError(null);

        const response = await fetch("https://jsonplaceholder.typicode.com/posts");

        if (!response.ok) {
          throw new Error("データの取得に失敗しました");
        }

        const data: Post[] = await response.json();
        setPosts(data.slice(0, 5)); // 最初の5件だけ使う
      } catch (e) {
        setError(e instanceof Error ? e.message : "不明なエラーが発生しました");
      } finally {
        setIsLoading(false);
      }
    }

    fetchPosts();
  }, []);

  if (isLoading) {
    return <p>読み込み中です...</p>;
  }

  if (error) {
    return <p>エラー: {error}</p>;
  }

  return (
    <main style={{ padding: "24px", fontFamily: "sans-serif" }}>
      <h1>記事一覧(外部APIから取得)</h1>
      {posts.map((post) => (
        <article
          key={post.id}
          style={{
            marginBottom: "16px",
            padding: "12px 16px",
            backgroundColor: "white",
            borderRadius: "8px",
            boxShadow: "0 1px 3px rgba(15,23,42,0.08)",
          }}
        >
          <h2 style={{ margin: "0 0 8px", fontSize: "18px" }}>{post.title}</h2>
          <p style={{ margin: 0, color: "#4b5563", fontSize: "14px" }}>{post.body}</p>
        </article>
      ))}
    </main>
  );
}
TSX

何が起きているかを丁寧に分解する

  1. state の準備
    posts … 取得した記事データの配列
    isLoading … 読み込み中かどうか
    error … エラーがあったかどうか
  2. useEffect で「初回に一度だけ fetch」
    依存配列が [] なので、コンポーネントがマウントされたタイミングで fetchPosts が一度だけ実行される。
  3. fetch の中身
    fetch(URL) で HTTP リクエストを送る。
    response.ok で 200 系かどうか確認し、ダメなら throw でエラーにする。
    response.json() で JSON をオブジェクト配列に変換。
    setPosts(data.slice(0, 5)) で state に保存。
    成功しても失敗しても finallyisLoading を false にする。
  4. 条件分岐で UI を切り替え
    読み込み中なら「読み込み中…」だけ表示。
    エラーがあればエラー文を表示。
    それ以外(正常にデータがある状態)なら、posts.map で記事をカード表示。

この 1 セットが、React / Next.js での「データ取得して画面に表示する」基本パターンです。


Next.js らしい取り方との関係(軽く)

ここまで話したのは「クライアント側(ブラウザ側)で useEffect + fetch して表示」というやり方です。
Next.js では他にも、

  • サーバーコンポーネントで async / await を使って fetch する
  • getStaticProps / getServerSideProps(旧来の仕組み)を使う

などいろいろな方法がありますが、
まずは

「クライアントコンポーネントで useEffectfetch を組み合わせて、
state に入れたデータを map で表示する」

この1パターンをしっかり身体に入れておくのが大事です。


まとめと小さな練習

ここまでを整理すると、

API は「このURLにアクセスすると、このルールでデータを返します」という窓口で、fetch はその窓口からデータを取ってくるための関数。
fetch(URL) のあとに response.json() を呼ぶことで、JSON を「JavaScriptのオブジェクト・配列」に変換して扱えるようになる。
React では、useEffect の中で fetchsetState という流れでデータを取得し、map で画面に表示するのが基本パターン。
読み込み中・エラー・正常時の3つの状態を isLoading / error / data のように state で管理し、条件分岐で UI を切り替えると、実用に近い画面構成になる。

練習としては、今回の PostsPage をベースに、

  • data.slice(0, 3) のように件数を変えてみる
  • title だけ表示する簡易版リストを作る
  • 別のダミーAPI(ユーザー一覧など)を使って同じパターンを組んでみる

あたりから試すと、「fetch → JSON → state → 表示」の流れがかなりしっくり来るはずです。

タイトルとURLをコピーしました