首页 文章

在多页面应用中使用React

提问于
浏览
85

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

我还没有在网上找到任何回答以下问题的内容:

How do I break up or bundle my React components across a multi-page app?

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

到目前为止,我正在尝试使用条件语句通过搜索React将呈现的容器的ID来呈现组件 . 我不是100%确定React的最佳实践 . 它看起来像这样 .

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

我仍然在阅读文档,但还没有找到我需要的多页面应用程序 .

提前致谢 .

4 回答

  • 60

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

    该应用程序不是一个完整的React App,我使用React进行动态Stuff,比如CommentBox,它是autark . 并且可以包含在任何具有特殊参数的点...

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

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

    逻辑非常简单:

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

    您可以在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组件 .

  • 8

    编辑:11/01/2015

    我正在从头开始构建一个应用程序,我正在学习,但我认为你所寻找的是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
    }
    

    试试看 . This教程是我对这个和其他相关主题的理解使我超过顶部的教程 .

    原始答案如下:

    我在这里寻找同样的答案 . 看看this post是否会激励你 . 如果您的应用程序与我的应用程序类似,那么它的区域变化很小,仅在主体中有所不同 . 您可以创建一个小部件,它负责根据应用程序的状态呈现不同的小部件 . 使用磁通体系结构,您可以调度导航操作,该操作可以更改您的主体窗口小部件切换的状态,从而有效地更新页面主体 .

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

  • 34

    你在使用CMS吗?他们倾向于喜欢改变可能会破坏你的申请的网址 .

    另一种方法是使用像React Habitat这样的东西 .

    有了它,您可以注册组件,它们会自动暴露给dom .

    注册组件:

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

    然后他们可以像你这样在你的dom:

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

    以上内容将自动替换为您的反应组件 .

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

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

    这将公开 size 作为组件的道具 . 有additional options用于传递其他类型,如json,数组,整数,浮点数等 .

相关问题