在React Router v4中验证URL参数

5 javascript validation reactjs react-router react-router-v4

我想找出一种/items/:id在React Router v4中验证这样的Route路径的方法.我想在继续将ItemPage组件或Redirect组件呈现到登录页面之前检查数据库中是否存在此项(因此需要Promise或异步调用).我一直在尝试遵循https://reacttraining.com/react-router/web/example/auth-workflow中的模式,但验证不需要异步调用.当我尝试做类似的事情

const ValidatedRoute = async ({ component: Component, ...rest }) => (
  <Route {...rest} render={props => (
    await param.isValid? (
      <Component {...props}/>
    ) : (
      <Redirect to={{
        pathname: '/',
        state: { from: props.location }
      }}/>
    )
  )}/>
)
Run Code Online (Sandbox Code Playgroud)

我得到Objects are not valid as a React child (found: [object Promise]).如何对Route参数进行异步验证?

小智 6

更新:我尝试了两种方法.

高阶组件:我创建了2个更高阶的组件,AuthenticatedRoute并且ValidatedRoute:

import React, { Component } from "react";
import { Redirect } from "react-router-dom";

let AuthenticatedRoute = ComposedComponent => class extends Component {
  render() {
    if (!sessionStorage.jwt) {
      return <Redirect to={{
        pathname: '/login',
        state: { from: this.props.location }
      }}/>
    }
    return <ComposedComponent {...this.props} />
  }
}

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

import React, { Component } from "react";
import { Redirect } from "react-router-dom";

let ValidatedRoute = ComposedComponent => class extends Component {
  state = {
    isValid: true
  }

  async componentDidMount() {
    this.setState({
      isValid: await this.props.validator(this.props.match.params.id)
    })
  }

  render() {
    if (!this.state.isValid) {
      return <Redirect to={{
        pathname: this.props.redirect,
        state: { from: this.props.location }
      }}/>
    }
    return <ComposedComponent {...this.props} />
  }
}

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

为了使用它们,我将用于该路由的组件包装起来AuthenticatedRoute(ValidatedRoute(component)).优点是,这允许整齐地组织经过身份验证和验证的路由,但这必须在组件本身中完成,而不是在路由器文件中完成.我只是在Router那里经常使用.所以在路径文件中调用它看起来像:

<Route exact path="/list/:id" render={(props) => <ProtectedComponent
              validator={Validator}
              redirect='/'
              {...props}
              />
            } />
Run Code Online (Sandbox Code Playgroud)

另一种选择是创建一个PrivateRoute组件:

import React, { Component } from "react";
import { Redirect, Route } from "react-router-dom";

class PrivateRoute extends Component {
  state = {
    authenticated: true,
    validated: true
  }

  async componentDidMount() {
    if (this.props.validator) {
      this.setState({
        validated: await this.props.validator(this.props.computedMatch.params.id)
      });
    }
  }

  render() {
    if (this.props.authenticate && !sessionStorage.jwt) {
      return <Redirect to={{
        pathname: '/login',
        state: { from: this.props.location }
      }}/>
    }

    if (!this.state.validated) {
      return <Redirect to={{
        pathname: this.props.redirect,
        state: { from: this.props.location }
      }}/>
    }

    return <Route {...this.props} />
  }
}

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

它必须被称为:

<PrivateRoute exact path="/list/:id"
          authenticate={true}
          component={ProtectedComponent}
          validator={validator}
          redirect='/'
        />
Run Code Online (Sandbox Code Playgroud)

仍感觉非常反模式和React-Router-V4文档对此并不多.我和HOC一起去了,因为它感觉更有条理.