React

コンポーネントベースの UI ライブラリで、宣言的な記法と仮想 DOM の差分計算で UI の更新を扱う

フロントエンドUI
React」の技術書を見る →

React とは

React は、Meta (旧 Facebook) が 2013 年にオープンソース化した UI ライブラリで、コンポーネントベースのアーキテクチャと宣言的な記法で UI を構築する。2026 年 8 月時点の最新安定版は 19.2 系である。

宣言的な記法と差分更新

宣言的とは、DOM をどう書き換えるかではなく、ある状態のときに画面がどう見えるかを書くという意味だ。状態が変わると React はコンポーネントを呼び直し、前回の描画結果と今回の結果を突き合わせて、差があるノードだけを必要最小限の操作で書き換える。この突き合わせの対象になるメモリ上のツリーが仮想 DOM と呼ばれる。

ここを「仮想 DOM だから速い」と覚えると判断を誤る。差分の計算自体は追加の仕事であり、必要な DOM 操作を人が最小限に書き切った場合より速くなる保証はない。得られるのは、状態が増えても更新経路を人が管理しなくて済む書きやすさと、更新漏れによる表示の食い違いが起きにくいことである。実際に描画が重い原因は差分計算より、状態を置く位置が上すぎて無関係な範囲まで描き直していることの方が多い。

コンポーネント

コンポーネントは props を引数に受け取り、描画結果を返す関数として書く。同じ props なら同じ結果を返す純粋な関数にしておくことが前提で、渡された props を書き換えたり描画の途中で外部の変数を更新すると、React が描画を捨てて呼び直したときに結果が変わって破綻する。

// 関数コンポーネント (現在の標準)
function UserCard({ name, email }: { name: string; email: string }) {
  return (
    <div className="card">
      <h2>{name}</h2>
      <p>{email}</p>
    </div>
  );
}

// 使用
<UserCard name="Alice" email="alice@example.com" />

Hooks

Hooks は 2019 年 2 月に公開された React 16.8 で導入された仕組みで、関数コンポーネントに状態管理副作用を持たせる。それ以前は、状態を持つコンポーネントはクラスとして書く必要があった。

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

  useEffect(() => {
    document.title = `Count: ${count}`;
  }, [count]); // count が変わるたびに実行

  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
Hook用途
useState状態管理
useEffect副作用 (API 呼び出し、DOM 操作)
useRefDOM 参照、値の保持 (再レンダリングなし)
useMemo計算結果のメモ化
useCallback関数のメモ化
useContextコンテキストの参照

Server Components (React 19)

Server Components は、バンドルより前に、クライアントや SSR 用のサーバーとは別の環境で描画されるコンポーネントである。動かす場は 2 通りあり、CI 上でビルド時に 1 回だけ実行する形と、リクエストごとに Web サーバーで実行する形のどちらも取れる。React 19 で安定版になった (ただしバンドラーやフレームワークを実装する側が触る下位 API は、19.x の minor 間で変わり得ると明示されている)。

// app/user-list.tsx (Server Component): 既定はこちら
async function UserList() {
  const users = await db.users.findMany(); // サーバーで直接 DB アクセス
  return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}
// app/search-box.tsx (Client Component)
'use client'; // ファイルの先頭に置く (関数の直前に書いても効かない)

function SearchBox() {
  const [query, setQuery] = useState('');
  return <input value={query} onChange={e => setQuery(e.target.value)} />;
}

境界の単位はファイルである。'use client' はそのモジュールと、そこから読み込んでいるモジュール群をまとめてクライアント側の扱いにする。入力欄 1 つのために置いた宣言が、同じファイルが読み込んでいるライブラリごとクライアントへ送られることになるため、対話が必要な部分は小さいファイルへ切り出す。逆に Server Component 側は DB 接続や鍵をそのまま扱える代わりに、状態や onClick のようなブラウザ側の仕組みを持てない。

Vue / Svelte との比較

選定で効くのは機能差より「誰が決めるか」の違いだ。React は状態管理・ルーティング・データ取得を外部の選択に任せるため、決める自由と決め続ける負担が同時に付いてくる。Vue と Svelte は公式が用意した道筋が太く、判断の回数を減らせる。

観点ReactVueSvelte
アプローチライブラリ (自由度高い)フレームワーク (規約あり)コンパイラ
テンプレートJSXSFC (template + script)SFC
状態管理Hooks, Zustand, JotaiComposition API, Pinia$: リアクティブ宣言
周辺ライブラリ選択肢が多く選定の判断が残る公式系 (Pinia 等) で揃う公式系 (SvelteKit) 中心
学習コスト中程度低い低い

Next.js との関係

React 単体はルーティング、SSR、ビルド設定を提供しない。Next.js がこれらを統合し、React アプリケーションのフルスタックフレームワークとして機能する。React の公式ドキュメントは新規アプリでフレームワークから始めることを勧めており、その一覧に App Router 版の Next.js と React Router を挙げている (2026 年 8 月時点)。Next.js が唯一の正解として指定されているわけではない。

落とし穴

再レンダリングを止めようとして useMemouseCallback を撒くのは、たいてい逆効果になる。どちらも比較と保持のコストを払う仕組みで、依存配列を 1 つ書き損ねれば古い値を掴んだままになる。先に見るのは状態を置く位置で、変わる値を上位に置いたために無関係な範囲まで描き直していないかを確認する方が効く。

リストの key にインデックスを渡すのも定番の事故だ。並び替えや先頭への挿入が起きると、同じインデックスに別の要素が来る。React はそれを同じ要素の更新と解釈するため、入力欄の値やスクロール位置が別の行に付いて回る。key には要素自身が持つ識別子を渡す。

この記事は役に立ちましたか?

関連用語

関連する記事