MVCのViewからReactコンポーネントへデータを渡す方法(実装例付き)
この記事では ASP.NET Core MVC と React(Vite +
TypeScript)を統合する方法を解説します。
ASP.NET Core MVC のサーバーサイドレンダリングと、React
のコンポーネント指向UIを組み合わせることで
- MVCの既存アプリを壊さずReactを導入
- ページ単位でReactを段階導入
- SPA化せずにモダンUIを実現
といった構成を実現できます。
この記事では以下を解説します。
- MVCのViewからReactコンポーネントへデータを渡す方法
- RazorとReactの安全なデータ連携
- Viteを使ったReactビルド構成
- MVC + React構成の実務ポイント
- よくあるエラーと対処方法
システム構成
今回の構成
ASP.NET Core MVC
│
├ Controller
│
├ View (Razor)
│ ↓ JSON
│
└ React (Vite + TypeScript)
処理の流れ
- Controllerがデータを取得\
- Razor ViewでJSONとして埋め込む\
- Reactコンポーネントがデータを読み込む\
- ReactがUIを描画
MVC → React データ受け渡し方法
MVCからReactへデータを渡す方法は主に2つあります。
data属性: シンプル・安全
グローバル変数: 複数Reactコンポーネントで共有
方法① HTMLのdata属性を使用する
最も安全で一般的な方法です。
HTML5では data-*
属性を使用してカスタムデータを埋め込むことができます。
React側では dataset APIで取得できます。
推奨:特定の React コンポーネントに特化した初期データを渡す場合。
欠点:非常に多くのデータや複雑なデータを渡す場合、HTML が肥大化する可能性があります。
Razor(View)
@using System.Text.Json
@{
var product = new { Id = 1, Name = "すごいウィジェット", Price = 10.11 };
var productJson = JsonSerializer.Serialize(product);
}
<div id="product-detail-root"
data-product='@Html.Raw(productJson)'>
</div>
<script type="module" src="/js/react/product.js"></script>
シリアライゼーションとエスケープの注意点
ASP.NET Core の C# オブジェクトを JavaScript で利用可能な JSON 形式に変換する場合は、
System.Text.Json.JsonSerializer.Serialize()
を使用するのが現在の標準的な方法です。
using System.Text.Json;
var product = new { Id = 1, Name = "すごいウィジェット", Price = 10.11 };
var productJson = JsonSerializer.Serialize(product);
この JSON を HTML に埋め込む際にはエスケープ処理に注意が必要です。
ASP.NET Core の Razor はデフォルトで HTMLエスケープを行います。
React側
import ReactDOM from "react-dom/client"
interface ProductProps {
id: number
name: string
price: number
}
function ProductDetail({ id, name, price }: ProductProps) {
return (
<div>
<h3>{name}</h3>
<p>ID: {id}</p>
<p>価格: {price.toFixed(2)}円</p>
</div>
)
}
const rootElement = document.getElementById("product-detail-root")
if (rootElement) {
const json = rootElement.dataset.product
if (json) {
const props: ProductProps = JSON.parse(json)
const root = ReactDOM.createRoot(rootElement)
root.render(
<ProductDetail {...props} />
)
}
}
方法② グローバル変数を使用する
複数のReactコンポーネントで同じデータを使用する場合は
windowオブジェクト
を使う方法が便利です。
推奨:ページ全体で共通して利用されるようなアプリケーションレベルの初期設定やユーザー認証情報などを渡す場合。
欠点:グローバルスコープを汚染する可能性がある。どのコンポーネントがどのグローバル変数を使ってもおかしくなる場合がある。型安全性を確保するために型定義の拡張が必要。
Razor
@{
var currentUser = new { Id = "user123", Name = "田中 太郎", IsAdmin = true };
var json = System.Text.Json.JsonSerializer.Serialize(currentUser);
}
<script>
window.APP_INITIAL_DATA = @Html.Raw(json);
</script>
<div id="user-profile-root"></div>
<script type="module" src="/js/react/profile.js"></script>
セキュリティ上の注意(XSS)
@Html.Raw() は HTMLエスケープを無効化するため注意が必要です。
もし以下のようなユーザー入力をそのまま出力すると
ブラウザで実行されてしまいます。
これを クロスサイトスクリプティング(XSS) と呼びます。
TypeScript型定義
global.d.ts
export {}
declare global {
interface Window {
APP_INITIAL_DATA?: {
Id: string
Name: string
IsAdmin: boolean
}
}
}
windowオブジェクトにカスタム プロパティを追加する場合
windowオブジェクトにカスタム プロパティを追加する際は、declare global構文を使って型定義を拡張することを忘れないでください。これは、TypeScript がコンパイル時にそのプロパティの存在を認識できるようにするためです。
Reactコンポーネント
import ReactDOM from "react-dom/client"
type UserProfileProps = {
id: string
name: string
}
function UserProfile({ id, name }: UserProfileProps) {
return (
<div>
<h3>ユーザープロフィール</h3>
<p>ID: {id}</p>
<p>名前: {name}</p>
</div>
)
}
const el = document.getElementById("user-profile-root")
if (el && window.APP_INITIAL_DATA) {
const { Id, Name } = window.APP_INITIAL_DATA
const root = ReactDOM.createRoot(el)
root.render(
<UserProfile id={Id} name={Name} />
)
}
MVC + React構成のメリット
この構成のメリット
- 既存MVCを壊さない
- SPA化しなくてもモダンUI
- SEOに強い
- Reactを段階導入できる
このため
業務系システムではよく採用される構成です。
まとめ
ASP.NET Core MVCとReactを統合する際のポイント
- MVC → React は JSONでデータ連携
- data属性またはグローバル変数を使う
- scriptは type="module"
この構成を使うことで
SPA化せずにReactを段階導入することが可能になります。