在React Router v4中验证URL参数

时间:2017-10-29 18:00:01

标签: javascript reactjs validation react-router react-router-v4

我想找出一种在React Router v4中验证像/items/:id这样的路径路径的方法。我想在继续将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 }
      }}/>
    )
  )}/>
)

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

1 个答案:

答案 0 :(得分:5)

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

高阶组件:我创建了2个高阶组件,AuthenticatedRouteValidatedRoute

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;

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;

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

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

另一种选择是创建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;

它必须被称为:

<PrivateRoute exact path="/list/:id"
          authenticate={true}
          component={ProtectedComponent}
          validator={validator}
          redirect='/'
        />

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