【问题标题】:How to handle async request in React-router wrapper如何在 React-router 包装器中处理异步请求
【发布时间】:2019-05-26 08:41:27
【问题描述】:

我想检查用户是否在我的 React 应用程序中进行了身份验证。使用this 指南。

我在 <Route /> 类上编写了一个包装器,用于检查用户是否通过了身份验证,然后我们渲染组件,如果没有,我们只是将他重定向到登录页面。

const IsAuthenticatedRoute = function ({ component: Component, ...rest }) {
    return (
        <Route {...rest} render={async (props) => {
            return (
                await store.isAuthenticatedAsync() === true // here is the point of troubles
                    ? <Component {...props} />
                    : <Redirect to={{
                        pathname: '/sign-in',
                        state: { from: props.location }
                    }} />
            )
        }} />)
}

我在我的路由器中这样使用它:

ReactDOM.render(
    <Provider store={appStore}>
        <Router>
            <div>
                <Switch>
                    <Route exact path='/' component={App} />
                    <IsAuthenticatedRoute path='/protected-route' component={Profile} />
                </Switch>
            </div>
        </Router>
    </Provider>
    ,
    document.getElementById('root')
)

我想向服务器执行我的异步请求以检查用户是否已通过身份验证。我试图通过await 调用将async 关键字添加到我的函数中,但它会产生错误:Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.。我几乎尝试使用承诺,但这也无济于事。当我在我的函数中使用Promise 并在.then() 运算符中返回&lt;Route /&gt; 时,React 告诉我:IsAuthenticatedRoute(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.

所以我希望处理我的异步功能,然后在我从服务器获得响应后,授予我的用户访问此页面的访问权限。是否只能向我的服务器发送同步请求,或者有其他方法可以保持我的代码异步并将用户传递到受保护的页面?

【问题讨论】:

  • 因为你在那里返回一个 Promise - 而不是一个组件。您应该为安全路由创建 HOC,检查权限(通过在异步检查期间显示一些加载程序或其他内容),如果不允许用户查看此组件,请执行重定向。

标签: javascript reactjs async-await react-router


【解决方案1】:

async 函数不能呈现为组件,因为您将呈现 Promise,而不是纯函数。如果纯函数返回组件的实例,则可以呈现纯函数。 Promise 必须先解决,然后才能呈现。

解决的办法是在组件挂载的时候启动异步调用,让组件有状态,这样调用解决的时候就可以变异。在等待响应时,您需要渲染一些东西。您可以渲染null,但加载微调器会更合适。这样我们就可以随时渲染一些内容,并且在尝试渲染尚未定义的组件时不会遇到错误。

这是我对组件外观的快速破解:

class RouteRender extends React.Component {
  constructor(props) {
    super(props)
    this.state = { authorized: null }
  }

  componentDidMount() {
    // setState is called once the asynchronous call is resolved.
    store.isAuthenticatedAsync().then(
      authorized => this.setState({ authorized})
    )
  }

  render() {
    if(this.state.authorized === true) {
      const { component: Component, componentProps } = this.props
      return <Component {...componentProps} />
    } else if(this.state.authorized === false) {
      return (<Redirect to={{
               pathname: '/sign-in',
               state: { from: props.location }
             }} />)
    }
    return <LoadingSpinner />
  }
}

const IsAuthenticatedRoute = function ({ component: Component, ...rest }) {
  return (
    // render is now a function rather than a Promise.
    <Route {...rest} render={props => <RouterRender componentProps={props} component={Component} />} />
  )
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-23
    • 1970-01-01
    • 1970-01-01
    • 2019-10-19
    • 2018-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多