ページ内で部分的に始める React 導入

すばる / su8ru


2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do

https://s.su8.run/260606-frontend-phpcon-do

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

自己紹介

すばる / su8ru

  • 北海道大学工学部情エレ 4 年
  • サークル:HUIT ex-部長 / Hupass
  • Twitter:@su8ru_n , GitHub: @su8ru
  • すきなもの:ヰ世界情緒
2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

もくじ

  1. 既存ページの一部だけ React で書きたい
  2. createRoot だけならすぐできるが……
  3. 我々が本当にほしいもの
  4. mount 先を用意する
  5. 初期状態を外部から渡したい
  6. build 成果物を head にいれる
2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

例:

Smarty の既存フォーム

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

前提:ページ自体はちゃんと動いている

フォームの一部だけ複雑になってきた

  • 複数チェックボックス
  • 初期選択
  • 条件付きの表示

-> これらを React で書きたい

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

そもそも:

ページごと React にすれば簡単では?

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

ページごと作り直すのは大変

  • 既存テンプレートでやっていることを全部移して、
  • 画面全体の挙動を再現する必要がある
  • サービス面なら工数を避ける場合もあるが、管理面なら…?

-> React がほしい部分だけを置き換えたい

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

フォームの一部だけ React で動かす

<div id="checkbox-group"></div>

<script type="module" src="/assets/islands.js"></script>
createRoot(document.getElementById("checkbox-group")!).render(
  React.createElement(CheckboxGroup)
);
2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

理屈としては、これだけ

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

我々が本当にほしいもの

  • JSX がほしい
  • TypeScript がほしい
  • npm package を使いたい
  • CSS もまとめて扱いたい

-> ビルドが必要

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

ここから急に考えることが増える

  • src/*.tsx を書く
  • バンドラで JS / CSS を生成する
  • hash 付きファイル名の JS / CSS を PHP から読む
  • デプロイフローに組み込む

React を動かすだけの話だったはずなのに……

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

Astro なら面倒を見てくれる

  • HTML を生成して mount 先を用意する
  • どこを hydrate するか決める
  • build した JS / CSS を差し込む

-> これらを自分でやる必要がある

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

1. mount 先を用意する

Smarty 側では「ここで CheckboxGroup を mount する」ということだけを書く

<div data-react-island="CheckboxGroup"></div>

この div の中だけ React が触る

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

文字列から React コンポーネントを render する

const islands = {
  CheckboxGroup,
} satisfies Record<string, ComponentType<unknown>>;

document.querySelectorAll("[data-react-island]").forEach((el) => {
  const name = el.getAttribute("data-react-island");
  const props = JSON.parse(el.getAttribute("data-props") ?? "{}");
  const Component = islands[name!];

  createRoot(el).render(<Component {...props} />);
});
2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

2. 初期状態を外部から渡したい

  • field name
  • 初期選択
  • 選択肢の label / value

→ props が必要

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

Smarty から React に値を渡したい

Smarty 側で JSON を埋め込む

<div
  data-react-island="CheckboxGroup"
  data-props='{$checkboxGroupPropsJson|escape:"html"}'
></div>

attributes に <" が入るとつらい
-> json_encode 後に HTML escape すると安全

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

3. build 成果物を head にいれる

  • build するとファイル名に hash が付く
  • 中身が変わるとファイル名も変わる

-> Smarty に直書きできない

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

Smarty から build 結果を読みたい

manifest は「entry 名」と「build 後のファイル名」の対応表

{
  "src/islands.tsx": {
    "file": "assets/islands-Bi7oDEnV.js",
    "css": ["assets/islands-lwNXSBIb.css"]
  }
}

-> Smarty は安定した entry 名だけ知っていればよい

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

Smarty 側には helper を置く

テンプレートには entry 名だけを書く

{react_assets entry="src/islands.tsx"}

<link rel="stylesheet" href="/assets/islands-lwNXSBIb.css">
<script type="module" src="/assets/islands-Bi7oDEnV.js"></script>
2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

manifest.json から展開する

  1. src/islands.tsx を entry として受け取る
  2. manifest から filecss を引く
  3. linkscript にして出力する
2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do
ページ内で部分的に始める React 導入 | su8ru

まとめ

  • 既存ページの一部だけ React にすることはできる
  • 小さく始めるだけなら createRoot で十分
  • ただし JSX / TypeScript / CSS / npm package を使うなら build が必要
  • mount 先、props、assets の受け口を用意しつつ分離するのが大切

すばる / su8ru

2026-06-06 | Frontend PHP Conference Hokkaido 2026 - #frontend_phpcon_do