ウェブ開発の世界では、ユーザー体験を支えるフロントエンド技術が年々進化しています。中でも「Vue.js」「React」「Angular」は“世界三大フロントエンドフレームワーク”と呼ばれる存在で、どれも高機能かつ広く採用されています。しかし、初めて学ぶ人にとって「どれを選べばいいの?」という疑問は尽きません。この記事では、それぞれのフレームワークの特徴を初心者にもわかりやすく解説し、簡単なサンプルコードと動作の流れを丁寧に解説します。最後には「買い物リストアプリ」を3つのフレームワークで実装し、比較しながら学べるようにしています。
Vue.js
概要
Vue.jsは、軽量で学習コストが低いことから、初心者に最も優しいフロントエンドフレームワークの一つです。HTML、CSS、JavaScriptの基本を活かしながら、少しずつ拡張していけるのが特徴です。リアクティブ(双方向データバインディング)な仕組みを持ち、ユーザーの入力や状態の変化に応じて自動で画面を更新します。Vueの「テンプレート構文」はシンプルで、HTMLに{{ message }}
のように変数を埋め込むだけで動的な表示が可能です。
また、Vueコンポーネントは単一ファイル(.vue
)で管理できるため、HTML・CSS・JSが分かりやすくまとまります。中小規模サイトから企業システムまで柔軟に対応でき、特にSPA(シングルページアプリケーション)開発に強みを持っています。
サンプル
カウンターアプリ
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>カウンターアプリ (Vue 3)</title>
</head>
<body>
<div id="app">
<h2>{{ count }}</h2>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
new Vue({
el: '#app',
data: { count: 0 },
methods: {
increment() { this.count++ },
decrement() { this.count-- }
}
})
</script>
</body>
</html>
コードレビュー
data
はアプリの状態(ここではcount
)を保持する領域で、{{ count }}
と書くとHTMLに即時反映されます。@click
はVue独自のクリックイベントディレクティブで、increment
やdecrement
を呼び出します。ボタンを押すたびに内部のcount
が変わり、Vueが自動的に再描画してくれるため、DOM操作を明示的に書く必要がありません。これがVueの「リアクティブな魔法」です。

React
概要
ReactはFacebook(現Meta)が開発したフレームワークで、コンポーネント志向の設計が特徴です。ユーザーインターフェイスを「部品」として再利用できる構造を持ち、大規模アプリケーションにも適しています。JSX(JavaScript + XML)という構文を使い、HTMLのような記述で動的要素を組み立てられます。
Reactの考え方は「状態(state)」を中心に据える点にあります。UIは状態の結果であるという発想で、setState
による更新が行われると、自動的に仮想DOM(Virtual DOM)が差分描画を行い、効率的に画面を更新します。これにより、大量のUI要素を持つアプリでも高速に動作します。
サンプル
カウンターアプリ
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>カウンターアプリ (React)</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
function Counter() {
const [count, setCount] = React.useState(0);
return (
<div>
<h2>{count}</h2>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
</div>
);
}
ReactDOM.render(<Counter />, document.getElementById('root'));
</script>
</body>
</html>
コードレビュー
useState
はReactのフックで、状態変数count
と更新関数setCount
を定義します。ボタン押下時にsetCount
を呼ぶと再描画が行われ、画面上のcount
が変化します。仮想DOMにより効率的に必要部分だけが更新されるため、高速でスムーズな動作を実現します。Reactは関数型アプローチを採用しており、データの流れが明確なのも魅力です。

Angular
概要
AngularはGoogleが開発したフルスタックなフレームワークで、他の2つと異なりTypeScriptをベースとしています。DI(依存性注入)やルーティング、フォームバリデーションなど、Webアプリに必要な機能が標準で揃っており、企業システムや大規模開発に適しています。
AngularはMVC(Model-View-Controller)思想を継承し、データの流れを明確に分離しています。また、双方向データバインディングによりユーザーの操作とモデルの状態が即時同期され、整合性を保ちやすい構造です。やや学習コストは高いものの、一度慣れれば開発効率が非常に高まります。
サンプル
カウンターアプリ
<!DOCTYPE html>
<html lang="ja">
<head>
<title>カウンターアプリ (Angular)</title>
<script src="https://unpkg.com/@angular/core@17/bundles/core.umd.js"></script>
<script src="https://unpkg.com/@angular/platform-browser-dynamic@17/bundles/platform-browser-dynamic.umd.js"></script>
<script src="https://unpkg.com/@angular/compiler@17/bundles/compiler.umd.js"></script>
</head>
<body>
<app-root>読み込み中...</app-root>
<script type="text/javascript">
const { Component, NgModule } = ng.core;
const { BrowserModule } = ng.platformBrowserDynamic;
@Component({
selector: 'app-root',
template: `
<h2>{{count}}</h2>
<button (click)="inc()">+</button>
<button (click)="dec()">-</button>
`
})
class AppComponent {
count = 0;
inc() { this.count++; }
dec() { this.count--; }
}
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
bootstrap: [AppComponent]
})
class AppModule {}
ng.platformBrowserDynamic.platformBrowserDynamic().bootstrapModule(AppModule);
</script>
</body>
</html>
コードレビュー
@Component
はコンポーネントを定義するデコレーターで、テンプレート内の{{count}}
とクラス変数が双方向で結びつきます。(click)="inc()"
のようなイベントバインディングで、クリック時にメソッドを実行します。Angularは内部で依存関係やモジュールを管理しているため、コード量は多いものの、堅牢な構造で大規模開発に最適です。

各フレームワークの比較表
項目 | Vue.js | React | Angular |
---|---|---|---|
開発元 | Evan You(元Google) | Meta(旧Facebook) | |
使用言語 | JavaScript | JavaScript(+JSX) | TypeScript |
学習難易度 | 低 | 中 | 高 |
特徴 | シンプルで導入容易 | コンポーネント志向・仮想DOM | フルスタック構成・大規模対応 |
用途 | 小〜中規模アプリ | 中〜大規模アプリ | 大規模・業務アプリ |
主な構文 | テンプレート構文 | JSX | TypeScriptデコレーター |
応用版(買い物リスト)
Vue.js版
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>買い物リストアプリ (Vue.js)</title>
</head>
<body>
<div id="app">
<input v-model="item" placeholder="商品を入力">
<button @click="addItem">追加</button>
<ul>
<li v-for="(todo, index) in todos">
<span :style="{textDecoration: todo.done ? 'line-through' : 'none'}">{{ todo.text }}</span>
<button @click="todo.done = !todo.done">済</button>
<button @click="removeItem(index)">削除</button>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
new Vue({
el: '#app',
data: { item: '', todos: [] },
methods: {
addItem() {
if (this.item) {
this.todos.push({ text: this.item, done: false });
this.item = '';
}
},
removeItem(i) { this.todos.splice(i, 1); }
}
})
</script>
</body>
</html>
React版
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>買い物リストアプリ (React)</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
function App() {
const [item, setItem] = React.useState('');
const [todos, setTodos] = React.useState([]);
const addItem = () => {
if (item) {
setTodos([...todos, { text: item, done: false }]);
setItem('');
}
};
const toggleDone = index => {
const newTodos = [...todos];
newTodos[index].done = !newTodos[index].done;
setTodos(newTodos);
};
const removeItem = index => setTodos(todos.filter((_, i) => i !== index));
return (
<div>
<input value={item} onChange={e => setItem(e.target.value)} placeholder="商品を入力" />
<button onClick={addItem}>追加</button>
<ul>
{todos.map((t, i) => (
<li key={i}>
<span style={{ textDecoration: t.done ? 'line-through' : 'none' }}>{t.text}</span>
<button onClick={() => toggleDone(i)}>済</button>
<button onClick={() => removeItem(i)}>削除</button>
</li>
))}
</ul>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
</script>
</body>
</html>
Angular版
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>買い物リストアプリ (Angular)</title>
<script src="https://unpkg.com/@angular/core@17/bundles/core.umd.js"></script>
<script src="https://unpkg.com/@angular/platform-browser-dynamic@17/bundles/platform-browser-dynamic.umd.js"></script>
<script src="https://unpkg.com/@angular/compiler@17/bundles/compiler.umd.js"></script>
</head>
<body>
<app-root>読み込み中...</app-root>
<script type="text/javascript">
const { Component, NgModule } = ng.core;
const { BrowserModule } = ng.platformBrowserDynamic;
@Component({
selector: 'app-root',
template: `
<input [(ngModel)]="item" placeholder="商品を入力">
<button (click)="addItem()">追加</button>
<ul>
<li *ngFor="let todo of todos; let i = index">
<span [style.textDecoration]="todo.done ? 'line-through' : 'none'">{{ todo.text }}</span>
<button (click)="toggleDone(i)">済</button>
<button (click)="removeItem(i)">削除</button>
</li>
</ul>
`
})
class AppComponent {
item = '';
todos = [];
addItem() {
if (this.item) {
this.todos.push({ text: this.item, done: false });
this.item = '';
}
}
toggleDone(i) { this.todos[i].done = !this.todos[i].done; }
removeItem(i) { this.todos.splice(i, 1); }
}
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
bootstrap: [AppComponent]
})
class AppModule {}
ng.platformBrowserDynamic.platformBrowserDynamic().bootstrapModule(AppModule);
</script>
</body>
</html>
総評
Vue.jsはとにかく「やってみよう」と思った瞬間に動かせる手軽さが魅力で、HTML感覚で始めたい人に最適です。Reactはデータの流れと状態管理の思想が明確で、アプリ開発の本質を学びたい人におすすめ。Angularはやや難しいですが、企業システムやチーム開発を見据えるなら将来性が高い選択です。
最初の一歩を踏み出すなら、まずVue.jsで「動く楽しさ」を感じ、その後Reactで「設計の美しさ」に触れると、自然にAngularの「体系的な強さ」も理解できるようになります。どのフレームワークも目的や規模に応じて正解になり得ます。大切なのは「自分の作りたいもの」に合った道を選ぶことです。
コメント