React と Vue.js の概要

フロントエンド開発で最も人気のある2つのフレームワーク(ライブラリ)、ReactVue.jsを比較します。

基本情報

項目ReactVue.js
開発元Meta (Facebook)Evan You + コミュニティ
初回リリース2013年2014年
最新メジャーReact 19Vue 3.5+
ライセンスMITMIT
GitHub Stars230k+210k+
分類UIライブラリプログレッシブフレームワーク

コードの書き方の違い

カウンターコンポーネント

React(関数コンポーネント + Hooks)

import { useState } from 'react';

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

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

Vue.js(Composition API + SFC)

<script setup>
import { ref } from 'vue';

const count = ref(0);
</script>

<template>
  <div>
    <p>カウント: {{ count }}</p>
    <button @click="count++">
      増やす
    </button>
  </div>
</template>

TODOリスト

React

import { useState } from 'react';

function TodoList() {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState('');

  const addTodo = () => {
    if (!input.trim()) return;
    setTodos([...todos, { id: Date.now(), text: input, done: false }]);
    setInput('');
  };

  const toggleTodo = (id) => {
    setTodos(todos.map(todo =>
      todo.id === id ? { ...todo, done: !todo.done } : todo
    ));
  };

  return (
    <div>
      <input
        value={input}
        onChange={(e) => setInput(e.target.value)}
        onKeyDown={(e) => e.key === 'Enter' && addTodo()}
      />
      <button onClick={addTodo}>追加</button>
      <ul>
        {todos.map(todo => (
          <li
            key={todo.id}
            onClick={() => toggleTodo(todo.id)}
            style={{ textDecoration: todo.done ? 'line-through' : 'none' }}
          >
            {todo.text}
          </li>
        ))}
      </ul>
    </div>
  );
}

Vue.js

<script setup>
import { ref } from 'vue';

const todos = ref([]);
const input = ref('');

function addTodo() {
  if (!input.value.trim()) return;
  todos.value.push({ id: Date.now(), text: input.value, done: false });
  input.value = '';
}

function toggleTodo(todo) {
  todo.done = !todo.done;
}
</script>

<template>
  <div>
    <input v-model="input" @keydown.enter="addTodo" />
    <button @click="addTodo">追加</button>
    <ul>
      <li
        v-for="todo in todos"
        :key="todo.id"
        @click="toggleTodo(todo)"
        :style="{ textDecoration: todo.done ? 'line-through' : 'none' }"
      >
        {{ todo.text }}
      </li>
    </ul>
  </div>
</template>

主な違い

観点ReactVue.js
テンプレートJSX(JS内にHTML)SFC(HTML/JS/CSS分離)
状態管理イミュータブル(setStateで更新)リアクティブ(直接変更可能)
イベントonClick, onChange@click, v-model
ループ{array.map(item => ...)}v-for="item in array"
条件分岐{condition && <div>...</div>}v-if="condition"
CSSCSS-in-JS, CSS Modules等Scoped CSS(SFC内)

リアクティビティの仕組み

React: イミュータブルな状態管理

// 状態の更新は必ずsetter関数を通す
const [user, setUser] = useState({ name: '田中', age: 30 });

// NG: 直接変更しても再レンダリングされない
user.name = '佐藤';

// OK: 新しいオブジェクトを作ってセットする
setUser({ ...user, name: '佐藤' });

Vue.js: Proxyベースのリアクティビティ

const user = reactive({ name: '田中', age: 30 });

// OK: 直接変更すると自動で再レンダリングされる
user.name = '佐藤';

// ref の場合は .value でアクセス
const count = ref(0);
count.value++;  // テンプレート内では .value 不要

エコシステム比較

ルーティング

ReactVue.js
公式なし(React Router が事実上標準)Vue Router(公式)
代表的なライブラリReact Router, TanStack RouterVue Router

状態管理

ReactVue.js
公式なしPinia(公式推奨)
代表的なライブラリZustand, Jotai, ReduxPinia

メタフレームワーク(SSR/SSG)

ReactVue.js
SSR/SSGNext.js, RemixNuxt
静的サイトAstro, GatsbyAstro, VitePress

UIコンポーネントライブラリ

ReactVue.js
代表的なものshadcn/ui, MUI, Ant DesignVuetify, Element Plus, PrimeVue

パフォーマンス

バンドルサイズ

ReactVue.js
コアライブラリ~45KB (gzipped)~34KB (gzipped)
最小構成react + react-domvue

ランタイムパフォーマンス

React 19のコンパイラとVue 3のリアクティビティシステムにより、どちらも十分に高速です。一般的なWebアプリケーションでは体感差はほぼありません。

最適化のアプローチ

React: React Compiler(自動メモ化)、React Server Components

// React 19: Compilerが自動で最適化するため、手動メモ化が不要に
function UserList({ users }) {
  // useMemo, useCallback が多くの場合不要
  return users.map(user => <UserCard key={user.id} user={user} />);
}

Vue.js: コンパイラによる静的解析と最適化

<!-- Vue 3: テンプレートコンパイラが自動で最適化 -->
<template>
  <div>
    <h1>タイトル</h1>  <!-- 静的ノード: 更新チェックをスキップ -->
    <p>{{ dynamicText }}</p>  <!-- 動的ノード: これだけ更新 -->
  </div>
</template>

学習コスト

React の学習曲線

  1. JSX の理解
  2. Hooks(useState, useEffect, useRef…)
  3. 状態管理のイミュータブルパターン
  4. レンダリングの最適化(memo, useMemo, useCallback)
  5. 外部ライブラリの選定(ルーティング、状態管理、フォーム等)

Vue.js の学習曲線

  1. テンプレート構文(v-if, v-for, v-model…)
  2. SFC(Single File Component)の構造
  3. Composition API(ref, reactive, computed, watch)
  4. 公式ライブラリ(Vue Router, Pinia)

Vue.jsは公式が提供する範囲が広いため、「何を使えばいいか」の判断が少なくて済みます。

TypeScript 対応

React + TypeScript

interface UserProps {
  name: string;
  age: number;
  onUpdate: (name: string) => void;
}

function UserCard({ name, age, onUpdate }: UserProps) {
  return (
    <div>
      <h2>{name} ({age}歳)</h2>
      <button onClick={() => onUpdate('新しい名前')}>更新</button>
    </div>
  );
}

Vue.js + TypeScript

<script setup lang="ts">
interface Props {
  name: string;
  age: number;
}

const props = defineProps<Props>();

const emit = defineEmits<{
  update: [name: string];
}>();
</script>

<template>
  <div>
    <h2>{{ name }} ({{ age }}歳)</h2>
    <button @click="emit('update', '新しい名前')">更新</button>
  </div>
</template>

選定ガイド

React を選ぶべきケース

  • 大規模チーム: エンジニアの採用がしやすい(求人数が多い)
  • React Native: モバイルアプリも同時に開発する場合
  • 柔軟性重視: ライブラリを自由に組み合わせたい
  • Next.js: SSR/SSGにNext.jsを使いたい

Vue.js を選ぶべきケース

  • 少人数チーム: 公式エコシステムが充実しており判断が少ない
  • 学習コスト重視: HTMLに近い構文で入りやすい
  • Scoped CSS: CSSのスコープ管理をシンプルにしたい
  • 段階的な導入: 既存プロジェクトの一部に組み込みやすい

まとめ

判断軸ReactVue.js
求人数
学習しやすさ
公式エコシステム△(選定が必要)
柔軟性
TypeScript
パフォーマンス

2026年時点では、どちらを選んでも間違いはありません。チームのスキルセット、プロジェクトの要件、採用市場を考慮して決定しましょう。


コンポーネントのpropsやAPIレスポンスの構造を確認するには、AssistyのJSONフォーマッターが便利です。