他ライブラリとの組み合わせ
HotwireやMPAのページの中にReactを埋め込むのは簡単です。Reactの公式サイトによると、Facebookも長らくこの使い方がメインでした。GitHubも同様です。GitHubの場合はTurbo中心で作られてページの中の一部分をReactで実装しています。
Apple StoreもMPAページの中にReactを埋め込んで使っています。ブラウザ側だけで製品のオプションを選択して、価格を表示しています。このような複雑なステートをフロンド側だけで管理するために使っているようです。なおAppleウェブサイトの他のページは、ほとんどがMPAになっています。必要なところだけReactを使っています。
一般的なページ、特にマーケティング的なページは、Reactの必要がありません。MPAでも十分ですし、ウェブデザイナーはMPAの方に馴染んでいることも多いでしょう。ほとんどのページをMPAで作り、複雑なステート管理が必要なところだけをReactで書くのは賢明な選択です。
Apple Storeを模写した例です。詳しい解説はこちらを確認してください。またデモはこちらに用意しています。
<%= provide :head, javascript_include_tag("react_iphone", "data-turbo-track": "reload", type: "module") %> <div class="container container-lg mx-auto px-4 pt-16"> <div class="mx-auto min-w-[1028px] lg:max-w-5xl"> <div id="root"></div> </div> </div> <% if @catalog_data %> <script type="application/json" id="catalog-data"> <% @catalog_data[:images].transform_values! { image_path(_1) } %> <%= @catalog_data.to_json.html_safe %> </script> <% end %>
javascript_include_tag "react_iphone"
でReactアプリの本体のreact_iphone.jsx
を読み込んでいます<div id="root"></div>
を設置しています<script type="application/json" id="catalog-data">
の箇所ではカタログのデータ(オプションごとの価格など)をJSON形式に変換し、記載しています
@catalog_data
をJSONとして出力するJSON APIを用意し、Reactコンポーネントからfetch()
で読み込みます。しかしこれは無駄なリクエストが発生しますので、遅延が大きくなりますimport React from "react"; import {createRoot} from "react-dom/client"; import {IPhoneShow} from "./react/components/IPhoneShow" document.addEventListener("turbo:load", () => { const dataJSON = document.getElementById('catalog-data').textContent const data = JSON.parse(dataJSON) const root = createRoot(document.getElementById("root")) root.render(<IPhoneShow catalogData={data}/>); });
turbo:load
イベントが発火し、以下の処理が行われます。なおturbo:load
はTurboが用意しているカスタムイベントで、Turboを使用しない場合はDOMContentLoaded
イベントを使うのが一般的です <script type="application/json" id="catalog-data">
にあったJSONのデータを読み込み、data
オブジェクトにセットしますIPhoneShow
コンポーネントにdata
をprops(catalogData
)として渡し、これを<div id="root">
の箇所に埋め込みます<script type="application/json" ...>...</script>
にデータを埋め込めばERBからReactにデータを渡せます。ダイナミックなコンテンツであっても、無駄なリクエストを送信せずに、Next.jsのSSRと同等の早さでページを表示できます