1. ホーム
  2. javascript

[解決済み] 複数ページのアプリでReactを使う

2022-06-13 02:02:38

質問

私はReactで遊んでいて、今のところとても気に入っています。私はNodeJSでアプリを構築しており、アプリケーション全体の対話型コンポーネントの一部にReactを使用したいと考えています。私はそれを単一ページのアプリにしたくありません。

私はまだ、次の質問に答えるウェブ上の何かを見つけていません。

複数ページのアプリにわたって React コンポーネントを分割またはバンドルするにはどうすればよいですか。

現在、私のすべてのコンポーネントは、アプリのいくつかのセクションでそれらをロードしないかもしれないにもかかわらず、1つのファイルになっています。

今のところ、私は React がレンダリングするコンテナの ID を検索してコンポーネントをレンダリングするために条件文を使用しようとしています。私はReactのベストプラクティスが何であるかを100%理解しているわけではありません。以下のような感じです。

if(document.getElementById('a-compenent-in-page-1')) {
    React.render(
        <AnimalBox url="/api/birds" />,
        document.getElementById('a-compenent-in-page-1')
    );
}

if(document.getElementById('a-compenent-in-page-2')) {
    React.render(
        <AnimalBox url="/api/cats" />,
        document.getElementById('a-compenent-in-page-2')
    );
}

if(document.getElementById('a-compenent-in-page-3')) {
    React.render(
        <AnimalSearchBox url="/api/search/:term" />,
        document.getElementById('a-compenent-in-page-3')
    );
}

私はまだドキュメントを読んでいて、複数ページのアプリに必要なものをまだ見つけていません。

事前にありがとうございます。

どのように解決するのですか?

現在、似たようなことをやっています。

アプリケーションは完全なReactアプリではありませんが、私はコメントボックスのような動的なもののためにReactを使用しています。そして、特別なパラメータを使用して、任意の時点で含めることができます。

しかし、私のすべてのサブアプリケーションは、単一のファイルに読み込まれ、含まれています。 all.js に読み込まれ、含まれるので、ページ間でブラウザによってキャッシュされます。

SSRテンプレートにアプリを含める必要がある場合、クラス "__react-root" と特別なIDを持つDIVを含める必要があります(レンダリングされるReactアプリの名前です)。

ロジックはとてもシンプルです。

import CommentBox from './apps/CommentBox';
import OtherApp from './apps/OtherApp';

const APPS = {
  CommentBox,
  OtherApp
};

function renderAppInElement(el) {
  var App = APPS[el.id];
  if (!App) return;

  // get props from elements data attribute, like the post_id
  const props = Object.assign({}, el.dataset);

  ReactDOM.render(<App {...props} />, el);
}

document
  .querySelectorAll('.__react-root')
  .forEach(renderAppInElement)


<div>Some Article</div>
<div id="CommentBox" data-post_id="10" class="__react-root"></div>

<script src="/all.js"></script>

編集

webpack はコード分割と LazyLoading を完全にサポートしているので、すべてのアプリを 1 つのバンドルで読み込む必要はなく、分割して必要に応じて読み込む例を含めることは理にかなっていると思いました。

import React from 'react';
import ReactDOM from 'react-dom';

const apps = {
  'One': () => import('./One'),
  'Two': () => import('./Two'),
}

const renderAppInElement = (el) => {
  if (apps[el.id])  {
    apps[el.id]().then((App) => {
      ReactDOM.render(<App {...el.dataset} />, el);
    });
  }
}