如何在react-router中调用getComponent时显示加载UI?

Dav*_*d M 6 javascript reactjs react-router react-redux

我是React的新手,在使用getComponent加载路径时,我无法弄清楚如何渲染"loading ..."屏幕.getComponent调用正常工作并显示组件,但UI上没有任何迹象表明请求和响应之间发生了任何事情.这就是我想弄清楚的.

import Main from './pages/Main.jsx';
import Test from './pages/Test.jsx';
import Home from './pages/Home.jsx';


var Routes = {
  path: "/",
  component: Main,
  indexRoute: {
    component: Home
  },
  childRoutes: [
    {
      path: "test",
      component: Test
    },
    {
      path: "about",
      getComponent: function(path, cb) {
        require.ensure([], (require) => {
          cb(null, require("./pages/about/About.jsx"));
        });
      }
    }
  ]
};

export default Routes;
Run Code Online (Sandbox Code Playgroud)

在尝试使用onEnter或getComponent函数强制"加载"组件显示失败后,我想也许我应该尝试使用Redux将加载状态设置为true/false并让我的主视图组件显示加载屏幕:

import React from 'react';
import {connect} from 'react-redux';

import NavBar from '../components/Navigation/NavBar.jsx';
import Footer from '../components/Footer.jsx';
import Loading from './Loading.jsx';
import navItems from '../config/navItems.jsx';
import setLoading from '../actions/Loading.jsx';

var Main = React.createClass({
  renderPage: function() {
    if (this.props.loading) {
      return (
        <Loading/>
      );
    } else {
      return this.props.children;
    }
  },
  render: function() {
    return (
      <div>
        <header id="main-header">
          <NavBar navigation={navItems}/>
        </header>
        <section id="main-section">
          {this.renderPage()}
        </section>
        <Footer id="main-footer" />
      </div>
    );
  }
});

function mapStateToProps(state) {
  return {
    loading: state.loading
  }
}

export default connect(mapStateToProps)(Main);
Run Code Online (Sandbox Code Playgroud)

如果我使用动作手动设置加载状态,这似乎有效,这是我想要做的.但是(我觉得这将是一个真正的noob问题)我无法弄清楚如何从路由器内访问存储/调度程序.

我不确定我是否使用了错误的搜索术语或者其他什么,但我完全没有想法,每一个反应路由器/ redux教程似乎都跳过我认为必须成为常见问题的东西.

任何人都可以指出我正确的方向(也让我知道我正在做什么是最好的做法?)?

编辑:我会尝试澄清这一点.在第一个代码块中,您可以看到,如果单击一个<Link to="/about">元素,则将触发getComponent函数,这将延迟加载About.jsx组件.我遇到的问题是我无法弄清楚如何显示某种加载指示器/微调器,它会在单击链接后立即显示,然后在组件加载后立即更换.

更多编辑:我已经尝试创建一个包装器组件来加载异步路由,它似乎工作,但它感觉非常hacky,我敢肯定这不是正确的方法去做这件事.路由代码现在看起来像这样:

import Main from './pages/Main.jsx';
import Test from './pages/Test.jsx';
import Home from './pages/Home.jsx';
import AsyncRoute from './pages/AsyncRoute.jsx';


var Routes = {
  path: "/",
  component: Main,
  indexRoute: {
    component: Home
  },
  childRoutes: [
    {
      path: "test",
      component: Test
    },
    {
      path: "about",
      component: AsyncRoute("about")
    }
  ]
};

export default Routes;
Run Code Online (Sandbox Code Playgroud)

AsyncRoute.jsx页面如下所示:

import React from 'react';

function getRoute(route, component) {
  switch(route) {
    // add each route in here
    case "about":
      require.ensure([], (require) => {
        component.Page = require("./about/About.jsx");
        component.setState({loading: false});
      });
    break;
  }
}

var AsyncRoute = function(route) {
  return React.createClass({
    getInitialState: function() {
      return {
        loading: true
      }
    },
    componentWillMount: function() {
      getRoute(route, this);
    },
    render: function() {
      if (this.state.loading) {
        return (
          <div>Loading...</div>
        );
      } else {
        return (
          <this.Page/>
        );
      }
    }
  });
};

export default AsyncRoute;
Run Code Online (Sandbox Code Playgroud)

如果有人有更好的想法,请告诉我.

Nic*_*ole 0

好吧,让我们看看我是否可以在这里阐明这一点:

我不知道如何从路由器内访问商店/调度程序

据我所知,没有必要这样做。您可以指定所有路由,列出应回答每个路由的组件(就像上面所做的那样),然后将每个组件连接到 redux 存储。对于连接,您的mapStateToProps函数可以以更简单的方式编写,如下所示:

export default connect(state => state)(Main);
Run Code Online (Sandbox Code Playgroud)

关于loading状态:我认为拥有缓慢加载的组件并在加载时显示等待指示器是朝着错误方向迈出的一步。我宁愿有一个快速加载组件,它从后端异步加载其所有数据,并且当数据尚不可用时,该组件会呈现一个等待指示器。一旦数据可用,就可以显示。这基本上就是您在第二次编辑中所勾勒的内容。

如果您可以将其从实际数据中剔除,即不存在数据 -> 显示加载屏幕/存在数据 -> 显示真实屏幕,那就更好了。这样,您就可以避免加载标志不同步时出现的问题。(从技术上来说:避免冗余。)

因此,我宁愿为加载屏幕创建一个独立的组件,并在每个单独的组件需要它时显示它,而不是使包装器变得通用。(这些需求是不同的,因此似乎很难以通用的方式处理这个问题。)这样的事情:

var Page = function(route) {
  return React.createClass({
    getInitialState: function() {
      // kick off async loading here
    },
    render: function() {
      if (!this.props.myRequiredData) {
        return (
          <Loading />
        );
      } else {
        return (
          // display this.props.myRequiredData
        );
      }
    }
  });
};
Run Code Online (Sandbox Code Playgroud)