路线授权HOC导致儿童重新安装3次

时间:2017-10-19 08:09:15

标签: reactjs redux react-router react-redux

我正在使用HOC组件来限制对未登录用户的路由访问。当从URL直接访问此路由时(在应用程序首次加载时),此HOC在安装或重新呈现时重新安装子组件的问题。例如,我在did mount组件中有3次PaperWorkProgress

路线定义:

<Route path="/paperwork/progress" component={RequireAuth(PaperWorkProgress)}/>

这里有HOC代码:

import React, {Component} from 'react';
import {connect} from 'react-redux';

export default function(ComposedComponent) {
  class Authentication extends Component {

    // check if token exists in storage
    componentWillMount() {
      const token = localStorage.getItem('token');
      if (!token) {
        const {pathname, search} = this.props.location;
        this.props.history.push({
          pathname: '/signin',
          search: `?redirect_to=${pathname}${search}`,
        });
      }
    }

    // additional check
    componentWillUpdate(nextProps) {
      if (!nextProps.loggedIn) {
        const {pathname, search} = this.props.location;
        this.props.history.push({
          pathname: '/signin',
          search: `?redirect_to=${pathname}${search}`,
        });
      }
    }

    render() {
      return <ComposedComponent {...this.props} />;
    }
  }

  function mapStateToProps(state) {
    return {loggedIn: state.session.loggedIn};
  }

  return connect(mapStateToProps)(Authentication);
}

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

这个问题可能已经有一段时间了,但是我刚刚遇到了同样的问题。

最后,我发现我的 HOC函数实际上是在每次路线更改时调用的

对我有用的是初始化时仅创建授权组件一次

const AuthorisedDashboard = requireLogin(Dashboard);

然后再使用

<Route path="/dashboard" component={AuthorisedDashboard} />

或者,您知道,如果仅在授权模式下使用过,则可以导出已应用HOC功能的组件。

答案 1 :(得分:0)

我不确定这会对重新渲染问题产生影响,但您的代码感觉不对。

首先,你似乎有两个真实来源,你的redux商店和localStorage,这使事情变得复杂。如果要从以前的导航信息“保湿”商店,则应使用createStore“preloadedState”参数,而不是每次在组件中进行检查。 Cf Redux doc以及来自Redux自己Video for persisting and rehydrating State创作者的视频。一旦您的状态仅来自您的商店,它就会变得更加简单。

其次,

当您推送到组件内部的历史对象时,感觉就像您正在改变组件自己的道具(因为历史是道具)。这对我来说很奇怪,可能是你问题的根源。

为什么不在渲染方法中使用重定向组件呢? cf React router docs。该组件看起来像这样(显然你也需要更改你的登录组件,就像在文档中一样)

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

export default function(ComposedComponent) {
  class Authentication extends Component {
    render() {
      return !this.props.loggedIn ? (
        <Redirect
          to={{
            pathname: "/login",
            state: { from: this.props.location }
          }}
          {...this.props}
        />
      ) : (
        <ComposedComponent {...this.props} />
      );
    }
  }

  function mapStateToProps(state, ownProps) {
    return { loggedIn: state.session.loggedIn, ...ownProps };
  }
  return connect(mapStateToProps)(Authentication);
}