React Router v4:导航更改时发送请求

时间:2018-03-11 22:08:34

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

我正在使用react-router v4编写身份验证代码,我正在使用带有渲染道具的PrivateRoute,例如文档:Redirects (Auth)

我要做的是:每当用户导航到路线时,我都会发送一个动作来向后端发出请求以验证他是否已登录。

像这样:

// App.js
class App extends Component {
  checkAuth = () => {
    const { dispatch, } = this.props;
    // callback to dispatch
  }

  render() {
    const props = this.props;

    return (
      <Router>
        <div className="App">
          <Switch>
            <Route exact path="/" component={Login} />

            <PrivateRoute
              exact
              path="/dashboard"
              component={Dashboard}
              checkIsLoggedIn={this.checkAuth}
            />

            {/* ... other private routes here */}

          </Switch>
        </div>
      </Router>
    );
  }

在PrivateRoute.js中,我正在侦听路由以检查它是否发生变化,但是当路由发生变化时,此函数被调用太多次,并且发送动作来发出请求是个问题。

// PrivateRoute.js
const PrivateRoute = ({ component: Component, auth, checkIsLoggedIn, ...rest }) => (
  <Route
    {...rest}
    render={props => {
      props.history.listen((location, action) => {

        if (checkIsLoggedIn) {
          // Here I check if the route changed, but it render too many times to make a request
          checkIsLoggedIn(); // here is the callback props
        }
      });

      if (auth.login.isLoggedIn) {
        return <Component {...props} />;
      } else {
        return <Redirect to={{ pathname: "/login", state: { from: props.location } }} />
      }


    }
    }
  />
);  

我需要一个帮助,以便在路线发生变化时找出一个调用后端的好方法。

1 个答案:

答案 0 :(得分:0)

创建Higher Order Component (HOC)是一种非常干净的方法。这样,您就不需要创建单独的PrivateRoute组件,只需要一行更改就可以将任何组件从公共转换为受保护,反之亦然。

这样的事情应该有效:

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

export function withAuth(WrappedComponent) {
    return class extends React.Component {
        constructor(props) {
            super(props);

            this.state = {
                isUserLoggedIn: false,
                isLoading: true
            };
        }

        componentDidMount() {
            // Check for authentication when the component is mounted
            this.checkAuthentication();
        }

        checkAuthentication() {
            // Put some logic here to check authentication
            // You can make a server call if you wish,
            // but it will be faster if you read the logged-in state
            // from cookies or something.
            // Making a server call before every protected component,
            // will be very expensive, and will be a poor user experience.
            this.setState({
                isUserLoggedIn: true,       // Set to true or false depending upon the result of your auth check logic
                isLoading: false
            });
        }

        render() {
            // Optionally, you can add logic here to show a common loading animation,
            // or anything really, while the component checks for auth status.
            // You can also return null, if you don't want any special handling here.
            if (this.state.isLoading) return (<LoadingAnimation />);

            // This part will load your component if user is logged in,
            // else it will redirect to the login route
            if (this.state.isUserLoggedIn) {
                return <WrappedComponent authData={this.state} {...this.props} />;
            } else {
                return <Redirect to={{ pathname: "/login", state: { from: props.location } }} />;
            }
        }
    }
}

一旦你有了这个组件,你需要做的就是在你想要保护的任何组件中使用HOC。例如,在您的情况下,Dashboard文件中的导出行将是这样的:

/* Dashboard.js */
class Dashboard extends React.Component { ... }

export default withAuth(Dashboard);

在您的App中,您可以使用简单的Route组件:

<Route exact path='/dashboard' component={Dashboard} />

您的App无需关心哪些路线受到保护,哪些路线不受保护。实际上,只有实际组件需要知道它们受到保护。

希望这会有所帮助。干杯! :)