こんにちは、かつコーチです。
前回は、LaravelとVue(Inertia.js)で簡単なTODOアプリを作りました。
今回は同じTODOアプリをReactでも作ってみて、Vue構成との違いを実際に比較検証していきます。
このシリーズもいよいよ最終回です、最後までお付き合いください。
なぜLaravel+Reactを検証するのか
「どちらを選ぶべきか」は現場でよく出る悩み
Laravelプロジェクトの新規立ち上げでは、「フロントはVueにするか、Reactにするか」という選択に必ずと言っていいほど直面します。
どちらもInertia.jsに対応しており、技術的にはほぼ同じことができます。
だからこそ、「機能でなく、何を基準に選べばいいのか」が分かりにくい、というのが正直なところです。
今回は、前回作ったVue版のTODOアプリと同じ機能をReactで実装し、実際に手を動かしたうえで比較していきます。
同じTODOアプリをReactで作ってみる
セットアップの違い
BreezeのInertiaインストール時に、Vueの代わりにReactを指定できます。
composer require laravel/breeze --dev
php artisan breeze:install react
npm install
npm run dev
コマンドの違いは vue を react に変えるだけで、Laravel側(Controller・ルーティング・マイグレーション)は前回とまったく同じものがそのまま使えます。
これはInertia.jsが「バックエンドとフロントエンドの技術選択を分離できる」設計になっているからこそのメリットです。
コンポーネント実装比較
前回のVueコンポーネントに対応する、Reactのコンポーネントを実装してみます。
// resources/js/Pages/Todos/Index.jsx
import { useForm } from '@inertiajs/react'
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'
export default function Index({ todos }) {
const { data, setData, post, reset, errors } = useForm({
title: '',
})
const submit = (e) => {
e.preventDefault()
post(route('todos.store'), {
onSuccess: () => reset('title'),
})
}
const toggleDone = (todo) => {
useForm({ is_done: !todo.is_done }).patch(route('todos.update', todo.id))
}
const remove = (todo) => {
useForm().delete(route('todos.destroy', todo.id))
}
return (
<AuthenticatedLayout>
<div className="max-w-xl mx-auto py-8">
<h1 className="text-xl font-bold mb-4">TODOリスト</h1>
<form onSubmit={submit} className="flex gap-2 mb-6">
<input
type="text"
value={data.title}
onChange={(e) => setData('title', e.target.value)}
placeholder="やることを入力"
className="border rounded px-3 py-2 flex-1"
/>
<button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded">
追加
</button>
</form>
{errors.title && <div className="text-red-500 text-sm mb-4">{errors.title}</div>}
<ul>
{todos.map((todo) => (
<li key={todo.id} className="flex items-center gap-2 border-b py-2">
<input
type="checkbox"
checked={todo.is_done}
onChange={() => toggleDone(todo)}
/>
<span className={todo.is_done ? 'line-through text-gray-400' : ''}>
{todo.title}
</span>
<button onClick={() => remove(todo)} className="ml-auto text-red-500 text-sm">
削除
</button>
</li>
))}
</ul>
</div>
</AuthenticatedLayout>
)
}
Vue版の useForm とほぼ同じAPIがReact版でも用意されており、フォームの状態管理・エラー表示の書き方は非常によく似ています。
一番の違いは、Vueが v-model や v-for などのテンプレート構文でHTMLに近い書き方をするのに対し、ReactはJSXの中でJavaScriptの式(mapや条件演算子)を直接埋め込む点です。
Vue/Inertia vs React/Inertiaの比較
学習コスト
Vueは、HTMLに近いテンプレート構文(v-if v-for v-model)を使うため、HTML/CSSの延長線上で学習しやすい傾向があります。
Reactは、JSXという「JavaScriptの中にHTMLのような記法を書く」独自の書き方に慣れる必要があり、最初のとっつきやすさではVueに分があると感じています。
一方で、Reactの「JavaScriptの機能をそのまま使ってUIを組み立てる」という考え方は、複雑な状態管理が必要になったときに応用が利きやすいという側面もあります。
エコシステム・求人動向
Reactは世界的なシェアが大きく、求人数・情報量ともに豊富です。
Vueも日本国内では根強い人気があり、特にLaravelとの組み合わせでの実績・情報が多いのが特徴です。
「グローバルな求人市場を意識するならReact」「日本語の情報・国内案件を重視するならVueも十分選択肢になる」というのが、私の肌感覚です。
TypeScriptとの相性
どちらもTypeScriptに対応していますが、Reactは元々TypeScriptとの親和性を意識して発展してきた経緯があり、型推論まわりの情報や事例がやや豊富な印象です。
Vue3もComposition APIの登場でTypeScriptとの相性はかなり改善されていますが、チームの型安全性を強く重視するプロジェクトでは、Reactを選ぶケースが多いように感じます。
比較の観点をまとめると、次のようになります。
| 観点 | Vue(Inertia) | React(Inertia) |
|---|---|---|
| 学習コスト | 比較的低い(HTMLに近い) | JSXに慣れが必要 |
| 求人・エコシステム | 国内で根強い人気 | グローバルでシェアが大きい |
| TypeScriptとの相性 | Composition APIで改善済み | やや情報・事例が豊富 |
| 状態管理が複雑な場合 | Piniaなどで対応 | 素のJSと状態管理ライブラリの選択肢が広い |
つまずきポイント:propsの型でハマった話
かつコーチが実際につまずいた話
Vue版からReact版に移植していたとき、propsの扱い方の違いでミスをしたことがあります。
❌ Before:Vueの感覚のままpropsを直接書き換えようとする
export default function Index({ todos }) {
const toggleDone = (todo) => {
todo.is_done = !todo.is_done // propsを直接書き換えようとした
}
return (
// ...
)
}
Vueのリアクティブなオブジェクトに慣れていたせいで、Reactでも同じ感覚で todo.is_done を直接書き換えようとしてしまいました。
Reactではpropsは読み取り専用として扱うのが原則で、直接書き換えても画面は再描画されず、「クリックしても見た目が変わらない」という現象に悩まされました。
✅ After:サーバーへのリクエストと再取得(Inertiaの仕組み)に任せる
export default function Index({ todos }) {
const toggleDone = (todo) => {
useForm({ is_done: !todo.is_done }).patch(route('todos.update', todo.id))
// レスポンス後、Inertiaが自動的にpropsを最新の状態に更新してくれる
}
return (
// ...
)
}
Reactでは「propsやstateを直接変更せず、更新用の関数やリクエストを通す」という原則を徹底することで、ようやく期待通りに動くようになりました。
VueとReact、どちらも「データが変わったら画面も自動で変わる」という仕組み自体は共通していますが、「データの変更の仕方」に対する考え方の違いを理解していないと、こうした落とし穴にはまりやすいと実感しました。
結論:どちらを選ぶべきか
判断基準の整理
ここまでの比較を踏まえると、判断基準は次のように整理できます。
- 初めてSPA的なフロントに触れるなら:HTMLに近い記法で学習コストが低いVueがおすすめ
- チームにReact経験者が多い、またはグローバル案件を意識するなら:Reactが有利
- 型安全性やエコシステムの厚みを最優先するなら:Reactに分がある場合が多い
- 日本語情報や国内のLaravel事例を重視するなら:Vueの情報の探しやすさが強み
技術的な優劣というより、「チームの経験」「案件の性質」「学習コストをどこまで許容できるか」で選ぶのが実務的な判断だと感じています。
幸い、どちらもInertia.jsを使えばLaravel側のコードはほぼ共通化できるため、「まずはどちらかで試してみて、合わなければ乗り換える」というハードルも決して高くありません。
まとめ
このシリーズでは、PHPの基礎文法から始まり、オブジェクト指向、PDOによるDB操作、エラー対処、そしてLaravelでのルーティング・Eloquent・認証・テスト・設計パターン・実践的なフロントエンド連携まで、合計100本の記事を通して一歩ずつ積み上げてきました。
最初の「PHPとは?」という記事から数えると、ずいぶん遠くまで来たなと、書いている私自身も感慨深いものがあります。
PHPの基礎を固め、Laravelの型に沿った書き方を覚え、Service・Repositoryのような設計パターンまで扱えるようになったあなたなら、実務のLaravelプロジェクトでも十分に戦えるはずです。
この記事のポイント
- Inertia.jsを使えば、Laravel側のコードを変えずにVue/Reactを切り替えて検証できる
- Vueは学習コストの低さ、Reactはエコシステムの厚みとTypeScriptとの相性が強み
- Reactでは「propsやstateを直接書き換えない」という原則を守ることが重要
- どちらを選ぶかは技術的な優劣ではなく、チームの経験や案件の性質で判断するのが実務的
シリーズを読み終えたあなたへ
PHP基礎編・Laravel基礎学習編、合わせて100記事、本当にお疲れさまでした。
ここまで一つひとつ手を動かしながら読み進めてくれたことに、心から感謝しています。
このシリーズは一旦ここで区切りとなりますが、次のテーマとして、JavaScript/Vue・Reactをさらに深掘りする発展編や、Python/Djangoなど、別言語・フレームワークのシリーズを企画中です。
公開の際にはまたこのブログでお知らせしますので、楽しみに待っていてもらえたら嬉しいです。
改めて、100記事完走おめでとうございます。
これからも一緒に、コツコツ学んでいきましょう。
