ずんだもん「ぼくはずんだもん。Web技術なんも分からんおじさんエンジニアなのだ!」
ある日のふたり
![]() |
![]() |
ずんだもん「ずん子ちゃん、最近『React』と【Vue.js』ってよく聞くけど、どっちが美味しいのだ?」
東北ずん子「ずんだもん、それは“ずんだもち”と間違えてるよ!でも、どっちを学ぶか迷う人が多いのは本当だよね。」
ずんだもん「そうなのだ!もし“ずんだ.js”があれば即決なのに…。でも現実はReactかVue.jsなのだ!」
東北ずん子「じゃあ、迷えるずんだもんのために、強みや弱みを表で分かりやすくまとめてみたよ♪」
比較表
東北ずん子「それぞれの特徴や学習難易度を表にしてみたから、まずは見てみてね♪」
項目 | React | Vue.js |
---|---|---|
強み | - 世界最大のシェア - 求人・案件が豊富 - Meta社のサポート - エンタープライズ実績 - 豊富なエコシステム - React Nativeでモバイル対応 |
- 学習コストが低い - HTML/CSSの知識で始めやすい - 日本語情報が豊富 - 日本コミュニティが強い - 開発効率が高い - シンプルな構文 |
弱み | - 学習難易度が高い - JSXやHooksなど独自概念 - 状態管理が複雑 - 初心者には敷居が高い |
- エコシステムが小さい - グローバル採用率が低い - 大規模企業での実績が少なめ |
学習難易度 | JavaScriptの知識必須。JSXやHooksなどの理解が必要。習得まで2-3ヶ月(基礎) | HTML/CSSの知識でOK。直感的な記述。習得まで1-2ヶ月(基礎) |
パフォーマンス | 大規模向き。最適化技術が豊富。仮想DOMで高速。 | 小中規模向き。初期ロードやメモリ効率が高い。仮想DOMで高速。 |
求人・市場価値 | 世界的に高い。 | 日本国内で高い。 |
将来性 | 国際的な案件・大規模開発で需要拡大 | 日本国内や中小規模案件で安定需要 |
ずんだもん「こうやって比べると、どっちも魅力があるのだ!自分に合った方を選ぶのが大事だね!」
サンプルコード
サンプル1:ボタンの処理
![]() |
![]() |
東北ずん子「ずんだもん、ReactとVue.jsって書き方もけっこう違うんだよ。サンプルで見てみよう!」
ずんだもん「ボタンを押すとカウントアップするやつ、どんな風に書くのか気になるのだ!」
React(関数コンポーネント+Hooks)
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>カウント: {count}</p>
<button onClick={() => setCount(count + 1)}>
カウントアップ
</button>
</div>
);
}
export default Counter;
Vue.js(Composition API)
<template>
<div>
<p>カウント: {{ count }}</p>
<button @click="count++">カウントアップ</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>
書き方の主な違い
項目 | React | Vue.js |
---|---|---|
UI定義 | JSX(JavaScript内でHTML風記述) | テンプレート(HTMLに近い構文) |
状態管理 | useStateフック | refでリアクティブ変数 |
イベント | onClick(キャメルケース) | @click(HTML属性風) |
構造 | 全てJS内で完結 | テンプレート+スクリプト分離 |
ずんだもん「Vue.jsの方がHTMLっぽい書き方だし、Reactは全部JavaScriptで書く感じなんだね~!」
サンプル2:テキスト入力とリアルタイム表示
![]() |
![]() |
ずんだもん「ずん子ちゃん、入力フォームで文字を打ったら、すぐ下に表示されるやつも見てみたいのだ!」
東北ずん子「もちろん!バインディングの仕組みが分かるサンプルだよ♪」
React
import React, { useState } from 'react';
function TextInput() {
const [text, setText] = useState('');
return (
<div>
<input
type="text"
value={text}
onChange={e => setText(e.target.value)}
placeholder="入力してね"
/>
<p>入力内容: {text}</p>
</div>
);
}
export default TextInput;
Vue.js
<template>
<div>
<input v-model="text" type="text" placeholder="入力してね" />
<p>入力内容: {{ text }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
const text = ref('');
</script>
ずんだもん「Vue.jsのv-modelは簡単で分かりやすいのだ!ReactはonChangeで値を更新するんだね~」
サンプル3:リストのレンダリング
![]() |
![]() |
東北ずん子「次は配列のリストを画面に並べるサンプルだよ。よく使うから覚えておくと便利だよ!」
ずんだもん「リスト表示はどっちもよく使うのだ!」
React
import React from 'react';
function ItemList() {
const items = ['ずんだ', 'もち', 'ずんだもち'];
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
export default ItemList;
Vue.js
<template>
<ul>
<li v-for="(item, index) in items" :key="index">{{ item }}</li>
</ul>
</template>
<script setup>
const items = ['ずんだ', 'もち', 'ずんだもち'];
</script>
ずんだもん「Vue.jsはv-forで、Reactはmapでリストを作るんだね!どっちもkeyが大事なのだ!」
サンプル4:条件分岐(if文による表示切り替え)
![]() |
![]() |
ずんだもん「ずん子ちゃん、条件によって表示を変える方法も知りたいのだ!」
東北ずん子「OK!たとえば「ログインしているかどうか」で表示を切り替えるサンプルを用意したよ♪」
![]() |
![]() |
React
import React, { useState } from 'react';
function LoginStatus() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
return (
<div>
<button onClick={() => setIsLoggedIn(!isLoggedIn)}>
{isLoggedIn ? 'ログアウト' : 'ログイン'}
</button>
<p>
{isLoggedIn ? 'ようこそ、ずんだもん!' : 'ログインしてください'}
</p>
</div>
);
}
export default LoginStatus;
Vue.js
<template>
<div>
<button @click="isLoggedIn = !isLoggedIn">
{{ isLoggedIn ? 'ログアウト' : 'ログイン' }}
</button>
<p>
<span v-if="isLoggedIn">ようこそ、ずんだもん!</span>
<span v-else>ログインしてください</span>
</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
const isLoggedIn = ref(false);
</script>
ずんだもん「Vue.jsはv-if/v-elseで、Reactは三項演算子で条件分岐するんだね!」
サンプル5:親子コンポーネントの連携(親→子へのprops、子→親へのイベント)
![]() |
![]() |
東北ずん子「最後は親子コンポーネントのやり取りだよ!親から子にデータを渡したり、子から親にイベントを伝えたりするのは実務でもよく使うよ!」
React
Parent.jsx
import React, { useState } from 'react';
import Child from './Child';
function Parent() {
const [message, setMessage] = useState('こんにちは!');
const handleReply = (reply) => {
setMessage(reply);
};
return (
<div>
<h2>親コンポーネント</h2>
<p>子からのメッセージ: {message}</p>
<Child onReply={handleReply} />
</div>
);
}
export default Parent;
Child.jsx
import React from 'react';
function Child({ onReply }) {
return (
<div>
<h3>子コンポーネント</h3>
<button onClick={() => onReply('ずんだもんからこんにちは!')}>
親にメッセージを送る
</button>
</div>
);
}
export default Child;
Vue.js
Parent.vue
<template>
<div>
<h2>親コンポーネント</h2>
<p>子からのメッセージ: {{ message }}</p>
<Child @reply="handleReply" />
</div>
</template>
<script setup>
import { ref } from 'vue';
import Child from './Child.vue';
const message = ref('こんにちは!');
function handleReply(reply) {
message.value = reply;
}
</script>
Child.vue
<template>
<div>
<h3>子コンポーネント</h3>
<button @click="sendReply">親にメッセージを送る</button>
</div>
</template>
<script setup>
const emit = defineEmits(['reply']);
function sendReply() {
emit('reply', 'ずんだもんからこんにちは!');
}
</script>
ずんだもん「Reactはpropsで関数を渡して、Vue.jsはイベント(emit)で親に伝えるんだね~!」
東北ずん子「そうだよ!どちらも親子間のやり取りはとても大事だから、しっかり覚えておこうね♪」
サンプル6:Graph API
![]() |
![]() |
ずんだもん「ずん子ちゃん、GraphAPIを使ってMicrosoft 365の情報を取得したいのだ!ReactやVue.jsでどうやって使うの?」
東北ずん子「GraphAPIはREST APIだから、アクセストークンを取得してHTTPリクエストを送ればOKだよ。ここでは、サインイン済みのユーザー情報(/me)を取得するサンプルを紹介するね!」
React
import React, { useEffect, useState } from 'react';
function GraphMe({ accessToken }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch('https://graph.microsoft.com/v1.0/me', {
headers: {
Authorization: `Bearer ${accessToken}`,
},
})
.then(res => res.json())
.then(data => setUser(data));
}, [accessToken]);
if (!user) return <div>Loading...</div>;
return (
<div>
<h2>ユーザー情報</h2>
<p>名前: {user.displayName}</p>
<p>メール: {user.mail}</p>
</div>
);
}
export default GraphMe;
- accessTokenはMicrosoft認証で取得したトークンを渡してください。
Vue.js
<template>
<div v-if="user">
<h2>ユーザー情報</h2>
<p>名前: {{ user.displayName }}</p>
<p>メール: {{ user.mail }}</p>
</div>
<div v-else>Loading...</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const props = defineProps(['accessToken']);
const user = ref(null);
onMounted(async () => {
const res = await fetch('https://graph.microsoft.com/v1.0/me', {
headers: {
Authorization: `Bearer ${props.accessToken}`,
},
});
user.value = await res.json();
});
</script>
- こちらもaccessTokenをpropsで受け取る形にしています。
ずんだもん「どっちもfetchでAPIを呼んでるのだ!アクセストークンをちゃんと用意して、Authorizationヘッダーにつけるのがポイントなんだね!」
東北ずん子「そうだよ。GraphAPIは他にも色々なリソースが取得できるから、エンドポイントを変えればTeamsやメール、カレンダー情報も取れるよ。Graph ExplorerやPostmanで試してみるのもおすすめだよ!」
東北ずん子「こうやって比べると、似てるところも違うところもあって面白いよね♪」
ずんだもん「サンプルを見ながら自分で書いてみると、もっと理解が深まるのだ~!」
技術選択の指針(まとめ)
![]() |
![]() |
ずんだもん「ずん子ちゃん、結局どっちを選べばいいのか迷っちゃうのだ…」
東北ずん子「プロジェクトやチームの状況によってオススメが違うから、表でまとめてみたよ!」
チーム・プロジェクト状況 | 推奨フレームワーク | 理由 |
---|---|---|
大規模・国際案件 | React | エコシステム・実績・求人・将来性が強い |
中小規模・日本国内 | Vue.js | 学習しやすく、開発効率が高い、日本語情報が豊富 |
初心者・HTML/CSS中心 | Vue.js | 直感的で始めやすい |
JS経験豊富・グローバル志向 | React | 市場価値・応用範囲が広い |
ずんだもん「自分の目標やチームの状況に合わせて選ぶのがポイントなのだ!」
まとめ
東北ずん子「最後に、もう一度ポイントをまとめるね!」
-
Reactは「世界標準」「大規模・高収入・グローバル向け」
-
Vue.jsは「学習しやすい」「日本国内・中小規模・初心者向け」
-
どちらも今後も需要が高く、キャリアやプロジェクトに合わせて選択するのがベストです。
![]() |
![]() |
ずんだもん「どっちも覚えておくと、きっと役に立つのだ!ずん子ちゃん、ありがとうなのだ~!」
東北ずん子「どういたしまして♪ みんなも自分に合ったフレームワークで楽しく開発してね!」
ずんだもん「ちなみにぼくは“ずんだもち.js”を開発したのだ!使うと画面が全部緑色になって、バグを発見すると“ずんだアラート”が鳴るのだ!」
東北ずん子「それ、デバッグしてる時に『ずんだずんだずんだ〜♪』って音楽が流れるやつ?」
ずんだもん「そうなのだ!でもみんな音楽に合わせて踊るから、もっとバグが増えちゃったのだ!…本末転倒なのだ!」
東北ずん子「それはもはやバグじゃなくて仕様だね(笑)」
利用キャラクター
- ずんだもん:VOICEVOX:ずんだもん
本記事で使用しているキャラクター画像の著作権は、それぞれの権利者に帰属します。
非商用目的での利用に基づき掲載しています。