在多页面应用程序中使用React


122

我一直在玩React,到目前为止,我真的很喜欢它。我正在使用NodeJS构建一个应用程序,并希望将React用于整个应用程序中的某些交互式组件。我不想使它成为单页应用程序。

我尚未在网上找到任何可以回答以下问题的信息:

如何在多页面应用程序中分解或捆绑我的React组件?

目前,即使我可能永远不会在应用程序的某些部分中加载它们,我的所有组件也都在一个文件中。

到目前为止,我正在尝试使用条件语句通过搜索React将在其中渲染的容器的ID来渲染组件。我不确定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')
    );
}

我仍在阅读文档,还没有找到多页应用程序所需的内容。

提前致谢。


尝试使用requirejs插件。
amit_183

2
如果您不介意ReactJs是一个非常大的JS库,需要针对每个页面进行初始化(如您所说的,您并不是在构建单个页面的应用程序),那么我不确定这对您是否重要将所有组件组合到一个文件中。它将被缓存在客户端上。页面加载时,将其render放在script块中正确的组件中。
有线草原

我遇到了同样的问题:我有一个应用程序可以在其他页面上加载其他大型库,而我只是根据访问者的需求加载react +一个库,而不是为防万一而加载四个大型库。
AJFarkas '16

Answers:


83

目前,我正在做类似的事情。

该应用程序不是完整的React App,我使用React进行动态处理,例如aututark的CommentBox。并且可以包含在具有特殊参数的任何点。

但是,我所有的子应用程序都已加载并包含在一个文件中all.js,因此浏览器可以跨页面对其进行缓存。

当我需要将应用程序包含在SSR模板中时,我只需要包含一个带有类“ __react-root”和特殊ID(将要呈现的React App的名称)的DIV。

逻辑非常简单:

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,因此我认为有必要提供一个示例,其中您无需将所有应用程序打包到一个捆绑包中,而是将它们拆分并按需加载。

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);
    });
  }
}

1
看起来很棒,有人在使用npm create-react-app时运行了此程序吗?我认为这对我不起作用...我现在让它与1应用程序一起运行,可以看到它如何工作,但是我的构建无法创建可以正常工作的生产构建。
Sprose

@Sprose也应该与create-react-app一起使用,我是否缺少某些东西?也许您可以在github上分享一个小例子,但事实并非如此,我看不出为什么不应该这么做
webdeb

1
@Sprose表示很抱歉,但是我想您尝试了完全不同的方法,即这种方法试图解决的问题。IMO create react app为您提供了一些易于创建的工具bundle.js。因此,我的答案是bundle.js在多个SSR站点中使用相同的代码并将其使用,并将许多不同的React应用程序加载到单个页面中。抱歉,如果我的回答不符合您的需求,请随时创建一个新帖子并描述您要做什么,我会尽力帮助您。
webdeb

1
@SorcererApprentice cra使用webpack,您必须弹出然后签出基本知识webpack.js.org/guides/getting-started/#creating-a-bundle
webdeb

1
@SorcererApprentice基本上有人在此页面上发布了webpack配置:stackoverflow.com/a/41857199/5004923
webdeb

52

您可以在webpack.config.js文件中为应用程序提供几个入口点:

var config = {
  entry: {
    home: path.resolve(__dirname, './src/main'),
    page1: path.resolve(__dirname, './src/page1'),
    page2: path.resolve(__dirname, './src/page2'),
    vendors: ['react']
  },
 output: {
    path: path.join(__dirname, 'js'),
    filename: '[name].bundle.js',
    chunkFilename: '[id].chunk.js'
  },
}

那么您可以在src文件夹中拥有三个不同的html文件以及它们各自的js文件(例如page1的示例):

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Page 1</title>
</head>
<body>
  <div id="app"></div>
  <script src="./vendors.js"></script>
  <script src="./page1.bundle.js"></script>
</body>
</html>

JavaScript文件:

import React from 'react'
import ReactDom from 'react-dom'
import App from './components/App'
import ComponentA from './components/ReactComponentA'
ReactDom.render(<div>
                  <App title='page1' />
                  <ReactComponentA/>
                 </div>, document.getElementById('app'))

然后可以为每个页面加载不同的React组件。


1
我在webex页面上阅读了以下内容。webpack version < 4 it was common to add vendors as separate entrypoint to compile it as separate file (in combination with the CommonsChunkPlugin). This is discouraged in webpack 4. Instead the optimization.splitChunks option takes care of separating vendors and app modules and creating a separate file. Do not create a entry for vendors or other stuff which is not the starting point of execution.那么,是否应该针对Webpack 4+更新此样本?
拉梅什(Ramesh)

32

我正在从头开始构建一个应用程序,并且正在学习中,但是我认为您正在寻找的是React-Router。React-Router将您的组件映射到特定的URL。例如:

render((
    <Router>
        <Route path="/" component={App}>
            <Route path="api/animals" component={Animals}>
               <Route path="birds" component={Birds}/>
               <Route path="cats" component={Cats}/>
            </Route>
        </Route>
        <Route path="api/search:term" component={AnimalSearchBox}>
    </Router>
), document.body)

在搜索情况下,“ term”可以作为AnimalSearchBox中的属性进行访问:

componentDidMount() {
    // from the path `/api/search/:term`
    const term = this.props.params.term
}

试试看。 教程使我对本主题及其他相关主题的理解达到最高水平。


原始答案如下:

我在这里找到同样的答案。看看这篇文章是否对您有所启发。如果您的应用程序类似于我的应用程序,则其区域变化很小,并且仅在主体上变化。您可以创建一个小部件,其职责是根据应用程序的状态呈现不同的小部件。使用助焊剂体系结构,您可以调度导航操作,该操作会更改正文小部件所切换到的状态,从而仅有效地更新页面的正文。

这就是我现在正在尝试的方法。


8
如果URL路径是由我的后端代码(在这种情况下为nodejs)创建的,该怎么办?请问Router工作它在单个页面应用程序以同样的方式?
Jose Carrillo 2015年

1
@Scott如果我不想公开具有特殊小部件的管理页面功能怎么办?使用react可以无需真实身份验证即可重新创建外观。
Kairat Kempirbaev

11

您正在使用CMS吗?他们倾向于喜欢更改URL,这可能会破坏您的应用程序。

另一种方法是使用类似React Habitat的东西。

使用它,您可以注册组件,它们会自动暴露给dom。

注册组件:

container.register('AnimalBox', AnimalBox);
container.register('AnimalSearchBox', AnimalSearchBox);

然后,它们在您的dom中可用,如下所示:

<div data-component="AnimalBox"></div>

<div data-component="AnimalSearchBox"></div>

以上内容将自动替换为您的react组件。

然后,您也可以自动将属性(或道具)传递给组件:

<div data-component="AnimalBox" data-prop-size="small"></div>

这将size作为道具公开给您的组件。还有其他传递其他类型的选项,例如json,数组,int,float等。


2

我知道问这个问题已经有一段时间了,但是希望这对某人有帮助。

如@Cocomico所述,您可以在webpack.config.js文件中为应用程序提供几个入口点。如果您正在寻找一个简单的Webpack设置(基于多个入口点的思想),该设置允许您将React组件添加到静态页面,则可以考虑使用以下方法:https : //github.com/przemek-nowicki/multi-page -app-with-react


-1

我建议您看看InertiaJS:https ://inertiajs.com/

使用Inertia,您可以像选择服务器端Web框架一样构建应用程序。您可以将框架的现有功能用于路由,控制器,中间件,身份验证,授权,数据获取等。

唯一不同的是您的视图层。视图不是JavaScript服务器渲染(例如Blade或ERB模板),而是JavaScript页面组件。这使您可以使用React,Vue或Svelte构建整个前端。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.