React Router 4:如何在Route的渲染方法中等待一个承诺解决?

时间:2018-06-19 12:22:51

标签: javascript reactjs react-router

我正在尝试实现功能,其中每个Route首先将等待一些Ajax Promise解决,然后才渲染该Route。我看到onEnter不再存在,所以我正在尝试render方法。

我的路线是这样定义的:

{cmsRoutes.map((route, idx) => {
              console.log(route.resolve)
              return route.component ? (<Route  key={idx} path={route.path} exact={route.exact} name={route.name} render={props =>{
               route.resolve()
               .then(({data})=>{
                 console.log(data)
                  return (
                <route.component {...props} />
              )
                }) 

              } } />)
                : (null);
            },
            )}

如您所见,它只是在某个数组上进行迭代,该数组保存每个路由的数据。路由对象的字段之一是“ resolve”,它指向一个函数,该函数返回一个promise。像这样一个:

const resolvemanageContactApplications = ()=> {
  return ajax('/contact')
};

执行此操作时,出现以下错误:

  

Route(...):渲染未返回任何内容。这通常意味着缺少return语句。或者,要不显示任何内容,请返回null。

这当然会发生,因为在执行ajax时,路由不会返回任何内容。问题:我该如何使React Router 4等待承诺解决方案?必须有某种方式。我记得AngaulrJS UI-Router实际上有一些“解析” api。

2 个答案:

答案 0 :(得分:5)

您需要在这里使用另一种方法。

您应该使用状态来存储ajax是否完成。然后,如果未完成ajax,则要渲染路线,您将不渲染任何内容(null或... loading),并使用ajax的结果渲染实际组件或所需的任何东西。

我可以看到您正在基于数据数组生成路由,并且要实现这一点,我将创建一个Component来包装数据加载条件。 它可以作为道具接收:

  • 解决(ajax函数)
  • 要渲染的组件

在componentDidMount和componentDidUpdate上执行ajax调用,并将state.waitingResolve设置为true,在解析的.then()上,将state.waitingResolve设置为false,并存储返回的数据到州。

在渲染器上,检查是否为state.waitingResolve,然后渲染null(或加载)或从道具接收的要渲染的组件。

看似复杂,但值得。

答案 1 :(得分:2)

您可以创建一些异步组件包装,例如:

class AsyncComponent extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      Component: null
    };
  }

  componentDidMount() {
    const { componentPromise } = this.props;
    componentPromise.then(component => this.setState({
      Component: component
    }));
  }

  render() {
    const { Component } = this.state;

    if (!Component) {
      return null; // You can return some spinner here
    }

    return (
      <Component {...this.props} />
    );
  }
}

并在路由器内部使用它:

<Route
  key={idx}
  path={route.path}
  exact={route.exact}
  name={route.name}
  render={props => (
    <AsyncComponent componentPromise={route.resolve} {...props} />
  )}
/>