プログラミング フレームワーク 公開日 2026.04.13 更新日 2026.06.13

React入門|初心者向けにコンポーネント・props・state・イベント処理の基本を整理

React をこれから学ぶ人向けに、React とは何か、コンポーネント、props、state、イベント処理、最初にどこまで分かればいいのかをやさしく整理した入門記事です。

先に要点

  • React は、画面を部品ごとに分けて作るための JavaScript ライブラリです(2026年6月時点の安定版は React 19.2 系)。
  • 初心者が最初に押さえたいのは、コンポーネント・props・state・イベント処理の4つです。
  • props は親から渡される値、state は自分の中で変わる値。この2つが混ざると「どこを直せば画面が変わるのか分からない」状態になります。
  • 初心者が必ず一度はやる事故が「state を直接書き換えたのに画面が変わらない」です。原因と直し方を本文で具体的に示します。

React ってよく聞くけど、結局なにをするものなの?」「JavaScript と何が違うの?」

フロントエンドを学び始めると、かなり早い段階で React の名前が出てきます。ただ、入門記事によっては最初から用語が多くて、コンポーネント・props・state・Hooks が一気に出てきて混乱しやすいです。

この記事では、React 公式 Learn / Quick Start(react.dev)を確認しながら、React を初めて触る人向けに「まず何が分かればよいか」を絞って整理します。さらに、この記事の後半では、入門書ではさらっと流されがちな props と state が混ざる失敗と、state を直接書き換えて再描画されない失敗を、実際のコードの before/after で具体的に示します。ここがいちばん詰まる場所だからです。

あとで Next.jsZustand に進む前提でも、ここを押さえておくとかなり楽になります。


Reactとは何か

React は、画面を小さな部品に分けて組み立てるための JavaScript ライブラリです。ざっくり言うと「同じ見た目や動きをする部品を、再利用しやすくするための道具」です。

たとえば、ブログや業務画面を作るときには、次のような部品が何度も出てきます。

  • ボタン
  • ヘッダー
  • 記事カード
  • メニュー
  • 入力フォーム

これらを毎回バラバラに書くのではなく、部品として作って使い回すのが React の基本です。

なお、React は単体では「画面を作る部分」だけを担当します。ルーティングや配信、サーバー側の処理は別の仕組み(たとえば Next.js)と組み合わせます。React 自体は SPA 的な作り方とも、SSRSSG を含む枠組みとも組み合わせられる、柔軟な土台だと考えると整理しやすいです。

JavaScriptだけで作るのと何が違うのか

JavaScript だけでも画面は作れます。ただ、画面が大きくなると、

  • どこで何を書き換えているのか分かりにくい
  • 同じ UI を何度もコピペしやすい
  • 状態が変わったときの更新が追いにくい

という問題が出やすくなります。

具体的に言うと、素の JavaScript では「データが変わったら、自分で document.querySelector して該当する DOM を書き換える」処理を、画面が変わるたびに手で書きます。ボタンの数字を1つ増やすだけでも、状態を持つ変数と、それを画面に反映する DOM 操作を、別々に同期させ続ける必要があります。これがズレると「変数は増えてるのに画面の数字が増えない」というバグになります。

React は、こうした「データと画面のズレ」を、コンポーネントと状態(state)の仕組みで自動的に合わせてくれます。「state を変えれば、画面はそれに合わせて自動で描き直される」。これが React の一番おいしいところです。


まず理解したい4つの基本

初心者は、最初から全部覚えなくて大丈夫です。まずは次の4つが分かれば、かなり前に進めます。

1. コンポーネント

画面を部品として分ける考え方です。ボタンやカード、一覧などを再利用しやすくします。

2. props

親コンポーネントから子コンポーネントへ渡す値です。子の側からは変更できない「読み取り専用」の入力です。

3. state

そのコンポーネントの中で変わる値です。開閉状態、入力値、選択中の項目などに使い、変えると再描画が起きます。

4. イベント処理

クリックや入力など、ユーザー操作に反応して state を変える処理です。

この4つを軸に見ると、React の全体像がかなり分かりやすくなります。とくに props と state の違いは、次の表のように「誰が変えられるか」「変えると何が起きるか」で並べると区別しやすいです。

観点 props state
どこから来る値か 親コンポーネントから渡される そのコンポーネント自身が持つ
誰が変えられるか 親だけ(子は変えてはいけない) 自分(set 関数で変える)
変えると何が起きるか 親が変えれば子に再描画が伝わる set 関数を呼ぶと再描画される
たとえると 外から受け取る「入力」 自分の中の「メモ帳」
代表例 商品名・価格・タイトル お気に入り中か・入力中の文字・開閉状態

コンポーネントとは何か

React では、画面を「部品」として分けます。たとえば記事一覧ページなら、こんなふうに分けられます。

  • ページ全体
  • 記事カード
  • カテゴリラベル
  • 検索フォーム
  • ページネーション

このとき、記事カードを1つのコンポーネントにしておけば、一覧の中で何度も再利用できます。

function ArticleCard() {
  return (
    <article>
      <h2>React入門</h2>
      <p>初心者向けに基本を整理した記事です。</p>
    </article>
  );
}

もちろん、これだけだと毎回同じ内容しか出ません。そこで次に出てくるのが props です。


propsとは何か

props は、親から子へ渡す値です。同じコンポーネントでも、渡す値を変えることで中身を変えられます。

function ArticleCard(props) {
  return (
    <article>
      <h2>{props.title}</h2>
      <p>{props.excerpt}</p>
    </article>
  );
}

使う側ではこう書けます。

<ArticleCard
  title="React入門"
  excerpt="コンポーネント・props・stateの基本を整理します。"
/>

実務では、引数の props. を毎回書くのは面倒なので、分割代入で受け取る書き方が主流です。中身は同じです。

function ArticleCard({ title, excerpt }) {
  return (
    <article>
      <h2>{title}</h2>
      <p>{excerpt}</p>
    </article>
  );
}

ここで一番大事なルールは、props は子の側で書き換えてはいけないということです。props は「親から借りている値」であって、子が勝手に変えると、親が持っている本当の値とズレてバグになります。子の中で値を変えたいなら、それは props ではなく state の出番です。


stateとは何か

state は、そのコンポーネントの中で変わる値です。たとえば次のようなものは state の代表例です。

  • メニューが開いているか
  • フォームに何が入力されているか
  • タブのどれが選ばれているか
  • 「もっと見る」で件数を増やしているか

React では、useState を使ってこうした値を持てます。

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>増やす</button>
    </div>
  );
}

この例で大事なのは、count が変わると画面も変わることです。setCount を呼ぶと、React は「state が変わった」と判断して、そのコンポーネントを必要なところだけ再描画します。逆に言うと、再描画が起きるのは set 関数(ここでは setCount)を呼んだときだけです。ここが後半の落とし穴に直結します。

propsとstateの違いをもう少し直感的に言うと

たとえば、店の商品カードを考えると分かりやすいです。

  • 商品名や価格を親が渡す → props
  • 「お気に入りにしたか」をそのカード内で持つ → state

つまり、props は受け取る情報、state は変化を持つ情報です。次の章では、この区別が崩れた実際のコードを before/after で見ていきます。


落とし穴その1:propsとstateが混ざる(実コードのbefore/after)

入門でいちばん多い事故が、「親から props でもらった値を、子の中で書き換えようとする」ことです。やりたいこと自体(編集できる入力欄を作る)は正しいのに、props と state の役割が混ざっているために動かない、という形でハマります。

悪い例(Before):propsを直接書き換えようとする

ユーザー名を表示して、その場で編集できる入力欄を作りたい、という想定です。

function NameInput({ name }) {
  return (
    <input
      value={name}
      onChange={(e) => {
        // props を直接書き換えようとしている(NG)
        name = e.target.value;
      }}
    />
  );
}

このコードは、入力しても文字がまったく変わりません。

  • 現象:キーボードを打っても入力欄の文字が変わらない(freezeしているように見える)。
  • 原因name は親から渡された props で、子の側で name = ... と代入しても React はそれを「state の変化」として認識しません。再描画も起きないので、value={name} は最初の値のまま固定されます。props はそもそも子から変えてはいけない値です。
  • 確認手順:React DevTools で NameInput を選び、Props 欄の name が入力しても変化していないことを見ます。さらに、コンポーネントの先頭に console.log('render', name) を置き、入力しても再描画ログが出ないことを確認します。
  • 回避:編集できる値は state にします。親からは「初期値」だけを props で受け取り、編集中の値はコンポーネント自身の state で持ちます。

良い例(After):初期値はprops、変わる値はstate

import { useState } from 'react';

function NameInput({ initialName }) {
  // 編集中の値は state として自分で持つ
  const [name, setName] = useState(initialName);

  return (
    <input
      value={name}
      onChange={(e) => setName(e.target.value)}
    />
  );
}

ポイントは2つです。1つめは、親から渡すのは「初期値(initialName)」だと名前で分かるようにしたこと。2つめは、変わる値は useState で state にして、変更は必ず setName を通すこと。こうすると入力のたびに再描画が起き、画面に反映されます。

「親が持っている値を、子で変えて、その結果を親にも返したい」場合は、親が state を持ち、子には「値」と「変更を知らせる関数」の両方を props で渡すのが定石です(lifting state up と呼ばれます)。

function Parent() {
  const [name, setName] = useState('');
  return <NameInput value={name} onChange={setName} />;
}

function NameInput({ value, onChange }) {
  return <input value={value} onChange={(e) => onChange(e.target.value)} />;
}

これで「state は親が1つだけ持つ」「子は表示と通知だけ」と役割が分かれ、混ざらなくなります。


落とし穴その2:stateを直接書き換えて再描画されない

もう1つの定番事故が、state を set 関数を通さずに直接書き換えることです。とくに配列やオブジェクトの state で起きます。React は「state が前と違う参照になったか」で再描画するかどうかを判断するため、元の配列を直接いじっても変化と見なされず、画面が更新されません。

悪い例(Before):配列をpushして再描画されない

「追加」ボタンを押すとリストに項目が増える、という想定です。

import { useState } from 'react';

function TodoList() {
  const [todos, setTodos] = useState(['牛乳を買う']);

  function add() {
    // 既存の配列を直接書き換えている(NG)
    todos.push('卵を買う');
    setTodos(todos); // 同じ配列を渡しているので変化と見なされない
  }

  return (
    <div>
      <ul>{todos.map((t, i) => <li key={i}>{t}</li>)}</ul>
      <button onClick={add}>追加</button>
    </div>
  );
}
  • 現象:ボタンを押しても画面のリストが増えない。なのにリロードしたり別の操作で再描画が走ると、まとめて増えていることがある。
  • 原因todos.push(...) は元の配列を書き換えるだけで、新しい配列を作りません。setTodos(todos) に渡しているのは「同じ参照」なので、React は「前と同じ=変わっていない」と判断し、再描画をスキップします。React の state 更新はイミュータブル(元を壊さず、新しい値を作って渡す)が前提です。
  • 確認手順add の中で console.log(todos.length) を出すと、配列の中身自体は増えている(push は効いている)のに画面が変わらない、という食い違いが見えます。React DevTools の state 欄でも、クリック直後は更新が反映されません。
  • 回避:既存の配列を壊さず、新しい配列を作って渡します。スプレッド構文(...)が定番です。

良い例(After):新しい配列を作って渡す

function add() {
  // 新しい配列を作って渡す(OK)
  setTodos((prev) => [...prev, '卵を買う']);
}

オブジェクトの state でも同じです。obj.done = true のように直接書き換えるのではなく、新しいオブジェクトを作ります。

// NG:直接書き換え
user.name = '田中';
setUser(user);

// OK:新しいオブジェクトを作る
setUser((prev) => ({ ...prev, name: '田中' }));

さらに、関数型の更新(setState(prev => ...))を使う理由も覚えておくと役立ちます。同じ処理の中で続けて2回更新したいとき、setCount(count + 1) を2回書いても、どちらも同じ古い count を参照するため結局1しか増えません。setCount(prev => prev + 1) なら最新の値を基準に計算されるので、ちゃんと2増えます。

やりたいこと NG(直接書き換え) OK(新しい値を作る)
配列に追加 arr.push(x); setArr(arr) setArr(prev => [...prev, x])
配列から削除 arr.splice(i, 1) setArr(prev => prev.filter((_, idx) => idx !== i))
オブジェクトの一部を変更 obj.k = v; setObj(obj) setObj(prev => ({ ...prev, k: v }))
数値を続けて2回増やす setN(n + 1); setN(n + 1) setN(p => p + 1); setN(p => p + 1)

イベント処理とは何か

React では、クリックや入力に応じて処理を書けます。これがイベント処理です。

function LikeButton() {
  const [liked, setLiked] = useState(false);

  return (
    <button onClick={() => setLiked(!liked)}>
      {liked ? 'お気に入り済み' : 'お気に入りする'}
    </button>
  );
}

ここでは、次の流れで動いています。

読み込み中...

React は、この「操作 → set 関数で state 変更 → 自動で再描画」という流れがすべての基本です。逆に言えば、set 関数を呼ばずに値だけ変えても画面は変わらない(前の章の落とし穴)ことが、ここからも分かります。

なお、初心者がよくやる細かいミスとして、onClick={handleClick()} のように関数に () を付けてしまう、というものがあります。これだと「クリックされたとき」ではなく「描画したその瞬間」に実行されてしまい、ボタンを押す前に動く(しかも再描画のたびに動く)バグになります。渡すのは関数そのものなので、onClick={handleClick}onClick={() => handleClick()} と書きます。


React初心者が最初につまずきやすいところ

1. propsとstateが混ざる

前述のとおり、これがかなり多いです。「外からもらう値(props)」と「自分で変える値(state)」が混ざると、何をどこで変えるべきか分からなくなります。迷ったら「この値、子が変える必要ある?」と自問し、変えるなら state、表示するだけなら props と切り分けます。

2. JavaScriptの文法で止まる

React が難しいというより、実は JavaScript の分割代入、配列メソッド(map / filter)、オブジェクト、アロー関数、スプレッド構文で止まっていることがあります。前章の [...prev, x]{ ...prev, k: v } が読めないなら、それは React ではなく JavaScript の補強が先です。

3. いきなり大きなアプリを作ろうとする

ログイン、API、検索、状態管理、ルーティングを最初から全部入れると、一気に分からなくなります。最初は、ボタン・カウンター・タブ切り替え・フォーム入力・一覧表示くらいの小さな UI から始める方が定着しやすいです。


実務ではReactをどう使うのか

実務で React がよく使われるのは、「画面部品が多く、更新も多い Web アプリ」です。

  • 管理画面
  • ダッシュボード
  • 会員向け画面
  • 検索画面
  • 条件切り替えが多い UI

要するに、ただの静的ページより、ユーザー操作に応じて表示がよく変わる画面と相性がよいです。

一方で、SEO や配信まで含めて考えたい公開サイトでは、React 単体より Next.js のような枠組みまで使うことが多くなります。Next.js はルーティング・SSR / SSGVercel などへの配信(デプロイ)までまとめて面倒を見てくれるので、公開サイトでは定番です。配信時には CDN でファイルを配り、DNS で独自ドメインをつなぐ、という流れになります。


最初はどこまで分かれば十分か

初心者の最初の目標は、次の状態です。

  • コンポーネントを作って分けられる
  • props で値を渡せる(子では変えないと分かっている)
  • useState で簡単な状態を持てる
  • 配列・オブジェクトの state を「新しい値を作って」更新できる
  • クリックや入力で表示を変えられる
  • 小さな一覧画面やフォームを作れる

ここまでできれば、React 入門としてはかなり十分です。とくに4番目の「イミュータブルに更新できる」が一度腹落ちすると、再描画されないバグでほとんど詰まらなくなります。そのあとで、ルーティング・API 通信・状態管理・Next.js に進めばよいです。最初から Redux や大規模設計まで追う必要はありません。


次に何を学ぶべきか

React の次に進む方向は、やりたいことで変わります。

画面中心のWebアプリを作りたい

この場合は、Next.js に進むのが自然です。React の上に、ルーティング、SSR、配信の仕組みが入ってきます。

状態管理を整理したい

複数の画面や部品で state を共有したくなったら、Context APIZustand が候補になります。「同じ state を、離れた複数のコンポーネントが見たい」と感じ始めたら検討のサインです。

APIとつなぎたい

外部 API や自作 API とつないで、一覧取得や登録処理を作る流れに進むと、実務感がかなり出てきます。


React入門に関するよくある質問

Q. React と JavaScript はどちらを先に学ぶべきですか?

A. JavaScript の基本(変数、関数、配列、オブジェクト、map/filter、スプレッド構文、async/await)を先に押さえる方が React の理解が早くなります。この記事のイミュータブル更新([...prev, x] など)がスッと読めるかが目安です。読めないうちは JavaScript の補強が先です。

Q. state を変えたのに画面が変わりません。なぜですか?

A. ほぼ100%、set 関数を通さず元の値を直接書き換えているか、同じ参照を渡しているかのどちらかです。arr.push()obj.k = v のあとに同じ配列・オブジェクトを set している場合は、スプレッド構文で新しい値を作って渡してください。本文の「落とし穴その2」が該当します。

Q. props を子の中で書き換えてもいいですか?

A. いけません。props は親から借りている読み取り専用の値です。子で変えたい値は state にし、親側の値も変えたいなら「値」と「変更用の関数」を props で渡す(lifting state up)方法を使います。

Q. クラスコンポーネントは今でも学ぶ必要がありますか?

A. 新規学習者は関数コンポーネントと Hooks だけで十分です。古いコードベースを触る可能性がある場合のみ、後からクラス記法を学ぶで問題ありません。

Q. useState と useReducer はどう使い分けますか?

A. 状態が単純(true/false、文字列、数値)なら useState、複数のフィールドが連動する複雑な状態なら useReducer が向きます。慣れるまでは useState を中心に書いて、更新ロジックが膨らんできたら useReducer に切り替えます。

Q. useEffect は怖い、と聞きました。なぜですか?

A. 依存配列の指定ミス、無限ループ、クリーンアップ漏れなど、初心者がはまりやすいポイントが多いからです。データ取得には TanStack Query などのライブラリを使う方が安全、という流れになっています。入門段階では「画面の表示は state で完結させ、useEffect は後回し」で構いません。

Q. React で API を呼ぶには何を使うべきですか?

A. シンプルなら fetch + useState、本格的に作るなら TanStack Query か SWR を推奨します。キャッシュ、再フェッチ、エラーハンドリングを自前で書かなくて済みます。

Q. React の学習にどれくらい時間がかかりますか?

A. JavaScript の基礎ができている人なら、簡単な Todo アプリが書けるレベルまで20〜40時間が目安です。実務で詰まらないレベルまでは、3〜6か月の継続学習が現実的です。


まとめ

React は、画面を部品として分けて再利用しやすくするための JavaScript ライブラリです。初心者は、まずコンポーネント・props・state・イベント処理の4つに絞って理解するとかなり進みやすくなります。

そのうえで、この記事で見た2つの落とし穴を覚えておくと事故が激減します。1つめは、props を子で書き換えようとして動かない問題(変わる値は state にする)。2つめは、配列やオブジェクトの state を直接書き換えて再描画されない問題(新しい値を作って set 関数で渡す)。どちらも「state を変えるときは必ず set 関数を通し、元を壊さず新しい値を渡す」と覚えれば回避できます。

次に進むなら、公開サイトや Web アプリ全体まで含めて学びたい場合は Next.jsは難しい?初心者がつまずきやすいポイントと学ぶ順番を整理、状態管理を整理したいなら Zustandとは?Reactの状態管理ライブラリの使い方とRedux・Context APIとの違いを解説 がつながりやすいです。


参考リンク

あとで見返すならここで保存

読み終わったあとに残しておきたい記事は、お気に入りからまとめて辿れます。