EXPLORE THE STACK

React入門環境構築からUIの実践まで

React入門をJavaScriptの基本から学ぶガイド。UIライブラリの役割、Viteでの環境構築、JSX・コンポーネント・props・useStateを解説します。チェックリストの完成コードと図解で、入力・追加・削除・状態管理を確認。エラー対処、公式資料、次に読む実践記事も紹介します。

内容更新 · 執筆・確認:y_ymo10

REACT.JS GUIDE

React入門の始め方

ReactはUIを作るJavaScriptライブラリです。このページの入門解説では、Viteで環境を構築し、JSX・props・useStateを使ったチェックリストを作ります。まず動かし、入力・追加・完了・削除の仕組みを確認しましょう。

  • 環境構築とファイルの役割を手順で確認
  • 完成コードと図解でprops・state・イベントを理解
  • エラー対処から7本の実践記事へ進む
このページの入門解説を読む

Reactの学習順序

初めての方は第1回から。復習したいテーマからも読めます。

  1. 第1回 · 入門読書リストで学ぶコンポーネントの基本
  2. 第2回 · 基礎useState・useEffectなどの基本Hooks
  3. 第3回 · 実践useReducerによる状態管理
  4. 第4回 · 実践useIdとフォームの関連付け
  5. 第5回 · 応用useMemo・useCallbackの使い方
  6. 第6回 · 応用useTransition・useDeferredValue
  7. 第7回 · 応用Fragment・StrictMode・Suspense・lazy
  8. 第8回 · 実践独自関数:normalizeTitle
  9. 第9回 · 実践カスタムフック:useToggle
  10. 第10回 · 実践APIのGET処理:fetchJson
  11. 第11回 · 応用通信状態の管理:useApiData
  12. 第12回 · 応用APIのPOST処理:postJson

Reactの実践記事一覧

12 ARTICLES

内容更新 · 執筆・確認:y_ymo10

React入門で最初に覚えたいのは、画面をコンポーネントに分け、propsでデータを渡し、stateの変化に合わせて表示を更新する流れです。この解説ではJavaScriptで書く小さなチェックリストを題材に、環境構築から操作の確認まで進めます。先に完成コードを動かしてから、分からない用語に戻って読んでも構いません。

Reactの基本と学習準備

HTML・CSS・JavaScriptとの関係

Reactはユーザーインターフェースを組み立てるJavaScriptライブラリです。WebページではHTMLが内容の構造、CSSが見た目、JavaScriptが計算や操作への応答を担当します。Reactを使ってもこの役割は残り、画面の一部分を「データを受け取り、表示内容を返す部品」として扱えるようになります。

例えば商品一覧なら、ページ全体、検索欄、商品カードを別々のコンポーネントにできます。同じカードを何度も書く代わりに、商品名や価格を渡して再利用します。一方、文章を載せるだけの小さなページでは、通常のHTMLとCSSで十分な場合もあります。入力や選択によって複数の表示が変わる画面を作ると、Reactの役割を理解しやすくなります。

学習前に、変数、関数、配列、オブジェクト、分割代入、map()、importとexportを確認しましょう。すべて暗記する必要はありません。サンプルを読んで「ここで関数を呼ぶ」「この配列から一覧を作る」と説明できれば、Reactの学習と並行して復習できます。JavaScriptの関数・モジュールと配列・オブジェクトが復習に使えます。

React・Vite・Next.jsを分けて考える

ReactはUIの部品と更新を扱います。Viteは開発サーバーやビルドを提供するツールです。Next.jsなどのフレームワークは、Reactに加えてページのルーティングやサーバー側の処理などをまとめて扱います。「Reactを学ぶこと」と「本番アプリの構成を決めること」は分けて考えましょう。

本ページでは仕組みを学ぶためにViteを使います。ルーティング、認証、データ取得、SSRが必要なサービスでは、フレームワークを使う構成も検討します。React公式にも、学習目的などでReactアプリをゼロから構築する方法が説明されています。Next.jsとの関係はNext.js入門ガイドでも確認できます。

Viteで環境を構築する

プロジェクトを作って起動する

Node.jsとnpm、コードを編集するエディター、ブラウザーを用意します。ターミナルで次のコマンドを順に実行してください。最初の2行はインストール済みのバージョン確認です。Viteが対応するNode.jsの条件は更新されるため、Vite公式の環境構築ガイドとインストール時の表示を確認してください。

Shell
node --version
npm --version
npm create vite@latest react-first-app -- --template react
cd react-first-app
npm install
npm run dev

生成時にパッケージの取得確認が出た場合は、表示された内容を確認して進みます。react-first-appは新しく作るフォルダー名です。起動後はターミナルに表示されたローカルURLをブラウザーで開きます。既に同じポートを使っていると別の番号になるため、URLを固定して覚える必要はありません。終了するときはターミナルでCtrl+Cを押します。

この例はJavaScript用のreactテンプレートです。TypeScriptを使う場合はreact-tsを選びますが、本ページのコードは.jsx用です。まずはJavaScript版で表示と操作を確認し、その後にpropsやイベントの型を追加すると、Reactと型の問題を切り分けやすくなります。

ファイルと実行コマンドの役割

index.htmlはブラウザーに読み込ませる入口です。src/main.jsxがReactのルートを作り、src/App.jsxでアプリの内容を定義します。src/App.cssやsrc/index.cssは見た目の設定、package.jsonは依存パッケージと実行コマンド、package-lock.jsonは解決された依存関係を記録するファイルです。

npm run devは編集しながら確認するためのコマンドです。完成後の出力はnpm run buildで作り、標準構成ではdistフォルダーに生成されます。npm run previewでビルド結果をローカル確認できますが、本番配信サーバーの代わりとして常用するものではありません。作業中に問題が起きたら、ブラウザーのエラーだけでなく、開発サーバーを起動したターミナルの表示も読みましょう。

JSXとコンポーネント

親のAppがstateを持ち、TaskItemへデータと更新用関数をpropsで渡す。子の操作を親が受け取りstateを更新する
データは親から子へ。操作は親から渡された関数で伝えます。

JSXはHTMLに似たJavaScriptの構文

JSXではタグの形でUIを書き、{}の中にJavaScriptの式を入れます。HTMLを文字列として組み立てる方法とは異なり、ビルドツールがReactで扱えるコードへ変換します。CSSクラスはclassName、ラベルの関連付けはhtmlForを使い、inputのような要素も<input />と閉じます。

コンポーネント名はLessonCardのように大文字で始めます。小文字のdivやbuttonは組み込みのHTML要素として扱われるためです。戻り値に並列の要素がある場合は、共通の親要素かFragmentの<>...</>でまとめます。書き方の詳細はReact公式のJSX解説を参照してください。

propsで内容を受け取る

次のコードは単独で試せる例です。src/App.jsxを置き換えると、同じLessonCardから内容の違う2つのカードが表示されます。propsは親から子へ渡す入力であり、子が受け取った値を直接書き換えるためのものではありません。

JSX
function LessonCard({ title, minutes }) {
  return (
    <section>
      <h2>{title}</h2>
      <p>学習の目安:{minutes}分</p>
    </section>
  );
}

export default function App() {
  return (
    <main>
      <h1>今日の学習</h1>
      <LessonCard title="JSXを書く" minutes={15} />
      <LessonCard title="イベントを扱う" minutes={20} />
    </main>
  );
}

title="JSXを書く"は文字列、minutes={15}は数値を渡しています。値に応じて表示が変わる一方、見出しと段落の構造は共通です。見た目の似た部分を無条件に細分化するより、繰り返し使う単位や、独立した役割を持つ部分から部品にすると読みやすくなります。propsの公式解説と読書リストの実践記事も参考にしてください。

stateとイベントの基本

クリックや入力から更新関数を呼び、次のstateでレンダーし、必要なDOM更新を画面に反映する流れ
stateを更新すると、新しい値を使って次の表示が作られます。

useStateで画面に必要な値を保持する

stateはコンポーネントが次のレンダーでも覚えておく値です。useStateは現在の値と更新関数を返します。通常のローカル変数を書き換えるだけではReactに画面更新を伝えられないため、クリック回数や入力内容には更新関数を使います。stateの仕組みを押さえると、画面が変わる理由を追いやすくなります。

次もsrc/App.jsxを置き換えて試す独立した例です。最初は0回と表示され、押すたびに1ずつ増えます。count + 1のように直前の状態から次を計算するときは、更新関数へ関数を渡す書き方が使えます。

JSX
import { useState } from 'react';

export default function App() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(previous => previous + 1);
  }

  return (
    <button type="button" onClick={handleClick}>
      練習した回数:{count}
    </button>
  );
}

onClick={handleClick}はクリック時に呼ぶ関数を渡します。onClick={handleClick()}と書くと表示処理の途中で実行され、意図しない更新を招きます。また、更新関数を呼んでも、そのイベント処理で参照中のcountがその場で別の値に置き換わるわけではありません。次のレンダーで新しいstateを使った表示が作られます。

Hooksと共有状態の置き場所

useStateなどのHooksは、関数コンポーネントやカスタムHookのトップレベルで呼び出します。条件分岐や繰り返し、クリック用の関数の中に置かないでください。複数の部品で同じ値を使うときは、共通の親にstateを置き、値と更新用の関数をpropsで渡す方法から考えます。

すべてをグローバルな状態管理へ集約する必要はありません。入力欄だけで使う値はその近くに置き、表示件数と一覧が共有するデータは親に置く、と役割で決めます。更新の種類が増えたらuseReducerの実践、離れた階層への共有が必要になったらuseContextを含む基本Hooksへ進んでください。

チェックリストを作る

入力・追加・完了・削除を実装する

ここからは完成形のコードです。前の例を残したまま追記せず、src/App.jsx全体を次の内容で置き換えてください。最初は「JSXを読む」が1件表示されます。入力した学習項目を追加し、完了にチェックを入れ、不要になった項目を削除できます。データ保存や通信は実装していないため、ページを再読み込みすると初期状態に戻ります。

JSX
import { useRef, useState } from 'react';
import './App.css';

function TaskItem({ task, onToggle, onRemove }) {
  return (
    <li className="task-row">
      <label>
        <input
          type="checkbox"
          checked={task.done}
          onChange={() => onToggle(task.id)}
        />
        <span className={task.done ? 'completed' : ''}>{task.title}</span>
      </label>
      <button type="button" onClick={() => onRemove(task.id)}
        aria-label={`${task.title}を削除`}>削除</button>
    </li>
  );
}

export default function App() {
  const [title, setTitle] = useState('');
  const [tasks, setTasks] = useState([
    { id: 1, title: 'JSXを読む', done: false },
  ]);
  const nextId = useRef(2);
  const completed = tasks.filter(task => task.done).length;

  function handleSubmit(event) {
    event.preventDefault();
    const trimmed = title.trim();
    if (!trimmed) return;
    const task = { id: nextId.current++, title: trimmed, done: false };
    setTasks(current => [...current, task]);
    setTitle('');
  }

  function toggleTask(id) {
    setTasks(current => current.map(task =>
      task.id === id ? { ...task, done: !task.done } : task
    ));
  }

  function removeTask(id) {
    setTasks(current => current.filter(task => task.id !== id));
  }

  return (
    <main className="lesson-app">
      <h1>学習チェックリスト</h1>
      <form onSubmit={handleSubmit}>
        <label htmlFor="task-title">次に学ぶこと</label>
        <div className="input-row">
          <input id="task-title" value={title} maxLength={80}
            onChange={event => setTitle(event.target.value)} />
          <button type="submit" disabled={!title.trim()}>追加</button>
        </div>
      </form>
      <p role="status">{tasks.length}件中{completed}件が完了</p>
      {tasks.length === 0 ? <p>学習項目を追加してください。</p> : (
        <ul className="task-list">
          {tasks.map(task => (
            <TaskItem key={task.id} task={task}
              onToggle={toggleTask} onRemove={removeTask} />
          ))}
        </ul>
      )}
    </main>
  );
}

CSSを設定して操作を確認する

テンプレートの初期スタイルが混ざらないように、src/index.cssは空にし、src/App.cssを次の内容で置き換えます。src/main.jsxはそのまま使います。チェックボックスのラベルをクリックできること、キーボードのTabキーで操作部品に移動できることも確認しましょう。

CSS
:root { font-family: system-ui, sans-serif; color: #15201f; background: #f7f8f5; }
* { box-sizing: border-box; }
body { margin: 0; }
button, input { font: inherit; }
button { padding: 0.6rem 0.9rem; cursor: pointer; }
button:disabled { cursor: default; }
button:focus-visible, input:focus-visible { outline: 3px solid #2477b8; outline-offset: 3px; }
.lesson-app { max-width: 42rem; margin: 3rem auto; padding: 1rem; }
.input-row { display: flex; gap: 0.75rem; margin-top: 0.5rem; }
.input-row input { flex: 1; min-width: 0; padding: 0.6rem; }
.task-list { list-style: none; padding: 0; }
.task-row { display: flex; align-items: center; gap: 1rem; padding: 1rem 0; border-bottom: 1px solid #d8ded8; }
.task-row label { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.task-row input { margin-right: 0.6rem; }
.completed { text-decoration: line-through; }

空欄や空白だけの入力では追加できません。「stateを学ぶ」を追加すると件数が2件になり、入力欄は空になります。チェックを入れると完了数が増え、文字に取り消し線が付きます。全項目を削除したら、案内文が表示されます。同じタイトルを2件追加しても、それぞれを別の項目として操作できれば、タイトルではなくIDで識別できています。

配列・key・フォームを読み解く

一覧はmap()で要素へ変換し、keyにはデータのIDを指定します。配列の位置やタイトルは、並べ替えや重複で不都合が起きるため、この例では生成時に決めたIDを使います。nextIdは再描画に使わない連番なのでuseRefで保持しています。このIDは1つのアプリ内だけで使う値で、保存や複数端末での共有には別途ID設計が必要です。一覧とkeyの公式解説も確認してください。

追加では配列の展開、完了の切り替えではmap()、削除ではfilter()で新しい配列を作ります。state内の配列をpush()で直接変更したり、元のオブジェクトのdoneを直接書き換えたりしない点が大切です。配列のstate更新で、追加・削除・置き換えの考え方を復習できます。

テキスト入力はvalueとonChange、チェックボックスはcheckedとonChangeを組み合わせています。画面に見えている値とstateを対応させるためです。送信時のpreventDefault()はフォーム送信によるページ移動を止めます。詳細はReactのinputリファレンスを参照してください。フォームを複数配置するときのIDはuseIdの実践記事へ進めます。

Effectの使い分けを学ぶ

表示の計算にEffectを足さない

完成コードでは、完了数をtasks.filter(...).lengthで求めています。既に持っている配列から計算できるので、完了数専用のstateと、それを同期するEffectを追加する必要はありません。保存する値を増やすほど、どちらか一方の更新漏れが起きやすくなります。

クリック後の追加や削除はイベントハンドラー、現在のデータから求める件数はレンダー中の計算、と整理しましょう。こうすると「何がきっかけで動く処理か」がコードから読み取れます。Effectが不要なケースでは、この判断が詳しく説明されています。

外部との同期には後始末も考える

useEffectは外部システムとの同期に使います。ブラウザーのイベント監視、タイマー、React以外のUIライブラリとの連携などでは、設定した処理を解除する後始末も検討します。依存配列は都合よく回数を抑えるために省略するものではなく、Effect内で参照する値との対応を確認します。

API通信を追加するなら、読み込み中・失敗・結果なしの表示に加え、古い通信結果で新しい状態を上書きしない仕組みも必要です。この入門例はローカルの状態管理に範囲を絞っています。通信やイベント監視へ進む前に、Effectによる同期の公式解説と基本Hooksのコード例を確認してください。

よくあるエラーの直し方

起動しない・画面が真っ白になる

まずターミナルで、今いるフォルダーにpackage.jsonがあるか確認します。npm run devが見つからない場合は、プロジェクトの外で実行していないか、依存パッケージのインストールが終わっているかを調べます。ブラウザーだけ再読み込みしても、開発サーバーが止まっている問題は解消しません。

JSXのエラーでは、閉じタグ、括弧、returnの位置、import先のファイル名を順に確認します。ファイル名の大文字・小文字の違いは、環境を変えたときに問題になる場合があります。エラー文の最初の行と示されたファイル・行番号を読み、複数箇所を一度に変えず、1つ直したら表示を確認してください。

入力やクリックで更新されない

入力できない場合はvalueだけ指定してonChangeを忘れていないかを確認します。ボタンでは関数を渡す場所で呼び出していないか、stateを直接代入していないかを見直します。フォーム内の削除ボタンにtype="button"がないと送信として動く場合があるため、ボタンの役割を明示しましょう。

開発中にログやEffectの実行が重なって見える場合は、StrictModeの追加チェックが関係していることがあります。チェックを消す前に、レンダー中にデータを書き換えていないか、Effectの後始末があるかを確認します。StrictModeの公式説明と組み込み機能の解説で、開発時と本番の挙動を区別できます。

次に学ぶことと疑問

どこまで理解したら次へ進める?

完成コードを見ずに書けることより、「どのstateが、どの操作で、どの表示を変えるか」を説明できることを目安にしてください。練習として、未完了だけを表示する切り替えや、完了済みをまとめて削除するボタンを追加してみましょう。表示対象を変えるだけなら元の配列を削除せず、表示用の配列を計算する方法を考えます。

部品を分ける練習には読書リストの入門記事、複数の更新操作を整理する練習にはuseReducerが使えます。動作に問題がない段階で、必要に応じてuseMemo・useCallbackやuseTransition・useDeferredValueに進みます。最適化のAPIを最初からすべて盛り込む必要はありません。

TypeScriptや学習教材はいつ使う?

JavaScriptでpropsとstateの流れを理解した後、TypeScriptでデータの形を表す練習へ進めます。型はコードの整合性を確認する助けになりますが、UIの使いやすさや通信先から届いたデータの正しさを自動で保証するものではありません。TypeScript入門ガイドから必要な基礎を選んでください。

本や動画を使う場合は、関数コンポーネントとHooksを扱っているか、環境構築の手順が手元のバージョンに合うかを確認します。丸写しで終わらせず、入力値や初期データを変えて結果を予想すると理解を確かめられます。無料で読めるReact公式のクイックスタートは基本の復習、React公式リファレンスはAPIごとの条件や注意点の確認に使い分けましょう。