ReactとPHPを組み合わせたい
弊社にはレガシーなPHPで作成されたシステムがあります。
全部をReactなどでリプレイスするのは現実的ではないです。
そのため、基本的な仕組みはPHPで行います。
ただ、新機能としてJSを用いてAPIを叩いて認証したり、DOMを操作したい場合があります。
技術選定候補
-
vanilla js
昔よりマシだが、さすがにaddEventlistnerとかDOM操作とかつらい -
jQuery
いまさら感漂う。久々に書いてみたけどReactなどに慣れるとDOM操作がしんどい。 -
lit
web componentsをつくればよろしいが、いろいろライブラリが枯れてない。
Reactならあのライブラリあるのにな〜とか、前つくったあれを使いたいな〜とか思う。 -
svelte, solid, react
まあどれもPHPとうまく組み合わせるのは結構難しいような……。
で、いろいろ考えた結果、phpのページAから読みだしたときは、この機能。
ページBから読みだしたときは、この機能というようにつくってみました。
Reactを呼び出す側
<div id="root" data-mode="auth"></div>
htmlというかphp側からは、こんな風にmodeを指定して呼び出します。
Reactでmodeを取得する
import React from "react";
import ReactDOM from "react-dom/client";
import { App } from "./App";
import { AppProvider } from "./providers/AppProvider";
const rootElement = document.getElementById("root");
const mode = rootElement?.dataset?.mode;
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<AppProvider>
<App mode={AppModeSchema.parse(mode)} />
</AppProvider>
</React.StrictMode>
);
modeをelement.dataset.modeで取得します。
modeについてはTypeScriptのユニオンで定義しておくのが良いと思います。
自分でつくったmodeなんだから違ったときはzodでしっかりエラーを出すのがよろしいかと。
一応zodSchemaの例。
export const AppModeSchema = z.union([z.literal("index"), z.literal("auth")]);
// type
export type AppMode = z.infer<typeof AppModeSchema>;
こんな感じですな。
ReactのApp.tsxで振り分けを行う
type AppProps = {
mode: AppMode;
};
export const App = ({ mode }: AppProps) =>
match(mode)
.with("index", () => <IndexPage />)
.with("auth", () => <AuthPage />)
.exhaustive();
ts-patternを使って網羅的なmatchを書くのがよろしいかと思います。
indexのときのコンポーネントとAuthのときのコンポーネントを作成して呼び出すわけです。
これで、indexページでは<div id="root" data-mode="index"></div>
とすれば良く
authページでは<div id="root" data-mode="auth"></div>
とすれば良いです。
まあReactの重さを考えると、litのほうが良いような気もしますが
React向けにつくられた便利なコンポーネントを使いたい、とかいろいろ考えるわけです。
svelteでweb componentsにするか、とか。
preact使うか……とか。
いろいろ考えるわけですが……。
もっと速度が必要になったときに考えましょう。
とりあえずPHPのいろいろなページでモードを変えて使えるReactでした。
もっと良さそうな方法あったら教えてください。
最初のうちはReactで、サイズが気になりだしたらpreactとかになりそうな予感がしています。