【问题标题】:React Router v4: Sending requests when navigation changesReact Router v4:导航更改时发送请求
【发布时间】:2018-08-19 21:47:54
【问题描述】:

我正在使用 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 } }} />
      }


    }
    }
  />
);  

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

【问题讨论】:

  • 您可以在我们的Dashboard组件的componentDidMount方法中向您的后端发出请求
  • @ArnoldGandarrilas 但我想在用户导航的每条私人路线中发出请求
  • PrivateRoute 是一个自定义的 React 组件。它与react-router无关。将其更改为有状态类,并在其 componentDidMount 方法中添加您的身份验证调用。
  • @FisNaN 我应该将其更改为使用渲染道具或 HoC 的类吗?
  • 临时检查是否有烫发是个好方法

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


【解决方案1】:

创建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 不需要关心哪些路由受保护,哪些不受保护。事实上,只有实际的组件需要知道它们是受保护的。

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

【讨论】:

  • 使用 HoC 是一个很酷的主意,但我试图避免使用 HoC,因为存在一个巨大的问题:如果我在“withAuth”中使用另一个具有相同名称的道具的 HoC,它将冲突!由于道具冲突,我仍然不知道使用 HoC 是否是一个好主意..
  • 我认为与从App 组件中抽象出身份验证逻辑所获得的好处相比,这是一个相对较小的问题。您可以将 authData 属性重命名为晦涩的名称,或者有意识地确保受保护的组件中没有属性冲突。否则,如果您觉得您的Dashboard 或其他组件不需要消耗authData,您甚至可以选择根本不传递。
猜你喜欢
  • 1970-01-01
  • 2019-03-19
  • 2018-10-05
  • 2017-10-17
  • 1970-01-01
  • 2017-08-20
  • 2017-10-23
  • 1970-01-01
相关资源
最近更新 更多