Auth Protected Routes React Router V4 - 传递道具

时间:2018-03-19 13:53:16

标签: reactjs react-router

我使用create-react-app创建了一个reactJS应用程序,使用Flux作为一种架构,我希望在不经过身份验证的情况下访问某些路由,而某些路由只能在经过身份验证时访问。使用flux设计模式我使用props将商店的状态向下传递到每个组件,因此存储状态可用于需要它的所有子组件。

我已经研究了文档here(下面还粘贴了这个示例),试图了解如何在我的应用中实现上述结果。

我无法看到我如何调整示例以将状态向下传递给受保护路由中调用的组件,而不使用显式名称(例如如何传递组件)来执行此操作。我想实现...

  1. 将组件传递给PrivateRoute,以便在我的用户通过身份验证时调用它。
  2. 将所有道具从父组件传递到PrivateRoute调用的组件(这是为了允许我通过道具级联存储状态,并在用户登录时检查存储状态)。
  3. 我想我或许误解了一些基本的东西。有人可以提出建议吗?

      import React from "react";
      import {
      BrowserRouter as Router,
      Route,
      Link,
      Redirect,
      withRouter
    } from "react-router-dom";
    
    ////////////////////////////////////////////////////////////
    // 1. Click the public page
    // 2. Click the protected page
    // 3. Log in
    // 4. Click the back button, note the URL each time
    
    const AuthExample = () => (
      <Router>
        <div>
          <AuthButton />
          <ul>
            <li>
              <Link to="/public">Public Page</Link>
            </li>
            <li>
              <Link to="/protected">Protected Page</Link>
            </li>
          </ul>
          <Route path="/public" component={Public} />
          <Route path="/login" component={Login} />
          <PrivateRoute path="/protected" component={Protected} />
        </div>
      </Router>
    );
    
    const fakeAuth = {
      isAuthenticated: false,
      authenticate(cb) {
        this.isAuthenticated = true;
        setTimeout(cb, 100); // fake async
      },
      signout(cb) {
        this.isAuthenticated = false;
        setTimeout(cb, 100);
      }
    };
    
    const AuthButton = withRouter(
      ({ history }) =>
        fakeAuth.isAuthenticated ? (
          <p>
            Welcome!{" "}
            <button
              onClick={() => {
                fakeAuth.signout(() => history.push("/"));
              }}
            >
              Sign out
            </button>
          </p>
        ) : (
          <p>You are not logged in.</p>
        )
    );
    
    const PrivateRoute = ({ component: Component, ...rest }) => (
      <Route
        {...rest}
        render={props =>
          fakeAuth.isAuthenticated ? (
            <Component {...props} />
          ) : (
            <Redirect
              to={{
                pathname: "/login",
                state: { from: props.location }
              }}
            />
          )
        }
      />
    );
    
    const Public = () => <h3>Public</h3>;
    const Protected = () => <h3>Protected</h3>;
    
    class Login extends React.Component {
      state = {
        redirectToReferrer: false
      };
    
      login = () => {
        fakeAuth.authenticate(() => {
          this.setState({ redirectToReferrer: true });
        });
      };
    
      render() {
        const { from } = this.props.location.state || { from: { pathname: "/" } };
        const { redirectToReferrer } = this.state;
    
        if (redirectToReferrer) {
          return <Redirect to={from} />;
        }
    
        return (
          <div>
            <p>You must log in to view the page at {from.pathname}</p>
            <button onClick={this.login}>Log in</button>
          </div>
        );
      }
    }
    
    export default AuthExample;
    

    以下是我实际代码的一部分......

    class Page extends React.Component{
      // constructor(props) {
      //   super(props);
      //   }
    
      render(){
        return(
        <Router>
          <div>
            <Route exact path="/" render={()=><HomePage {...this.props}/>}/>
            <Route path="/login" render={()=><LoginPage {...this.props}/>}/>
            <PrivateRoute exact path="/protected" component={Main} extra="Boo!"/>
          </div>
        </Router>);
      }
    }
    
    const PrivateRoute = ({ component: Component, ...rest }) => (
      <Route
        {...rest}
        render={(props) =>
          (console.log(this.props.extra) || 1) ? (
            <Component {...props} />
          ) : (
            <Redirect
              to={{
                pathname: "/login",
                state: { from: props.location }
              }}
            />
          )
        }
      />
    );
    

    This.props.extra未定义。

1 个答案:

答案 0 :(得分:2)

如果您正在寻找一种方法将额外的道具传递给PrivateRoute,您可以这样做:

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route
    {...rest}
    render={(props) =>
      (console.log(this.props.extra) || 1) ? (
        <Component {...props} {...rest} />
      ) : (
        <Redirect
          to={{
            pathname: "/login",
            state: { from: props.location }
          }}
        />
      )
    }
  />
);

然后

<PrivateRoute exact path="/protected" component={Main} extra="Boo!"/>

Main现在应该会收到extra道具(以及pathexact)。