【问题标题】:React router 4: How to wait for a promise to resolve, inside render method of Route?React路由器4:如何在Route的render方法中等待一个promise解决?
【发布时间】:2018-11-28 09:56:28
【问题描述】:

我正在尝试实现功能,其中每个 Route 将首先等待一些 ajax 承诺解决,然后才会呈现路由。我看到onEnter已经不存在了,所以我正在尝试渲染方法。

我的路线是这样定义的:

{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”,它指向一个函数,该函数返回一个承诺。喜欢这个:

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

执行此操作时,我收到以下错误:

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

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

【问题讨论】:

    标签: javascript reactjs react-router


    【解决方案1】:

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

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

    【讨论】:

    • 我明白了。所以我基本上需要把这个逻辑移出路由器
    • 所以我对它进行了测试,稍作调整,它可以工作,但不是我想要的方式。发生的情况是,我之前的组件从屏幕上卸载并消失,而不是什么都没有出现,直到 promise 得到解决。这不是我想要实现的用户体验。我需要的是让原始屏幕保持存在,直到承诺得到解决。想象一下它就像旧的服务器端渲染:只有当 http 请求返回时 - 原始页面与新页面切换。这就是为什么我试图从路由器做到这一点
    • 对此有很多讨论:stackoverflow.com/questions/37849933/…。我不能用 onEnter 事件来做,但有更好的机会直接处理历史事件处理程序。但我不建议你实现这样的用户体验,因为它会降低响应能力。也许您想触发一个异步操作(例如在按钮中),当它完成时,它会调用 history.push 在数据已经加载后进行路由更改
    【解决方案2】:

    您需要另一种方法。

    您应该使用状态来存储您的 ajax 是否已完成。然后,要渲染路由,如果 ajax 未完成,您可以不渲染任何内容(null 或 ...loading),并使用 ajax 的结果渲染实际组件或您想要的任何内容。

    我可以看到您正在根据数据数组生成路由,为此我将创建一个组件来包装数据加载条件。 它可以作为道具接收:

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

    在componentDidMount和componentDidUpdate上进行ajax调用,将state.waitingResolve设置为true,在resolve的.then()上,将state.waitingResolve设置为false,并将返回的数据也存储到状态中。

    在渲染时,您检查是否state.waitingResolve,并渲染 null(或 ...正在加载)或您从 props 收到的要渲染的组件。

    它可能看起来很复杂,但它是值得的。

    【讨论】:

    • 是的,看起来或多或少像 Yuriy Yakym 提供的。我会尝试这种方法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    • 2015-05-17
    • 1970-01-01
    • 2016-10-14
    • 1970-01-01
    • 2019-05-28
    • 2020-06-23
    相关资源
    最近更新 更多