如何更新高阶组件

时间:2019-02-13 09:33:15

标签: javascript reactjs react-router

我在ReactJS中创建了路由数组

const routes = [
  { id: 0, path: '/', view: Home, parent: 0 },
  { id: 1, path: '/a', view: Home2, parent: 0 },
  { id: 2, path: '/b', view: Home3, parent: 1 }
]

创建了具有Author的HOC,当未登录用户时,它应返回到父路由。当我要进行路由(未登录)时,可以正常使用withAuth将其返回到父路由,但是当我在路由上并且注销页面没有刷新并且我留在已登录用户的路由上。

import React, { Component } from "react";
import AuthHelper from "./AuthHelper";

export default function withAuth(AuthComponent) {
  const Auth = new AuthHelper();

  class AuthWrapped extends Component {
    constructor(props) {
      super(props);

      this.state = {
        confirm: null,
        loaded: false
      };
    }

    checkLogged = () => {
      if (!Auth.loggedIn()) {

        const parent = this.props.parent;
        const obj = this.props.routes
        .filter(v => v.id === parent);
        this.props.history.replace(obj[0].path);

      } else {
        try {
          const confirm = Auth.getConfirm();
          this.setState({
            confirm: confirm,
            loaded: true
          });
        } catch (err) {
          Auth.logout();
          this.props.history.replace("/");
        }
      }
    }

    componentDidMount() {
      this.checkLogged();
    }

    render() {
      if (this.state.loaded) {
        if (this.state.confirm) {
          return (
            <AuthComponent
              history={this.props.history}
              confirm={this.state.confirm}
            />
          );
        } else {
          return null;
        }
      } else {
        return null;
      }
    }
  };

  return AuthWrapped;
}

2 个答案:

答案 0 :(得分:1)

我相信您使用身份验证系统的方式有误
在React中,一切都应该以分层的方式存在。

在您的情况下,您具有将更改的Auth状态,并且当loginIn状态更改时,所有内容都应重新呈现。正确的方法是使用Context API处理登录状态,因此当状态更改时,整个屏幕将重新呈现


这是您解决问题的方法:

AuthContext.js

const AuthContext = React.createContext();

export class AuthProvider extends React.Component {
  state = {
    isLoggedIn: false,
  };

  login = (username, password) => {
    someLoginRequestToServer(username, password).then(response => {
      this.setState({
        isLoggedIn: response.isLoggedIn,
      });
    });
  };

  logout = () => {
    someLogoutRequestToServer().then(() => {
      this.setState({ isLoggedIn: false });
    });
  };

  render() {
    return (
      <AuthContext.Provider
        value={{
          loggedIn: this.state.isLoggedIn,
          login: this.login,
          logout: this.logout,
        }}>
        {this.props.children}
      </AuthContext.Provider>
    );
  }
}

export const AuthConsumer = AuthContext.Consumer;

SomeCustomAuthComponent

class CustomAuthComponent extends React.Component {
  render() {
    return (
      <AuthConsumer>
        {({ loggedIn, login, logout }) => (
          <div>
            <p>You Are {loggedIn ? 'Logged in' : 'Logged out'}</p>
            <button onClick={loggedIn ? () => logout() : () => login('abcd', '12345')} />
          </div>
        )}
      </AuthConsumer>
    );
  }
}

或者您可以使用redux进行状态管理,并使用react-redux,因为它使用了底层的react Context API。

希望这对您有帮助! :)

答案 1 :(得分:0)

问题出在这里

componentDidMount() {
 this.checkLogged();
}

您正在检查是否仅在安装组件时(实例化之后)才记录用户。您应该在每次页面更新时都对其进行检查,例如,必须使用componentDidUpdate钩子来确定一种处理该机制的方法。

export default function withAuth(AuthComponent) {
  const Auth = new AuthHelper();

  class AuthWrapped extends Component {
    constructor(props) {
      super(props);

      this.state = {
        confirm: null,
        loaded: false
      };
    }

    checkIsNotLogged = () => {
      const parent = this.props.parent;
      const obj = this.props.routes
        .filter(v => v.id === parent);
      this.props.history.replace(obj[0].path);
    }

    checkLogged = () => {
      if (!Auth.loggedIn()) {
        this.checkIsNotLogged();

      } else {
        try {
          const confirm = Auth.getConfirm();
          this.setState({
            confirm: confirm,
            loaded: true
          });
        } catch (err) {
          Auth.logout();
          this.props.history.replace("/");
        }
      }
    }

    componentDidMount() {
      this.checkLogged();
    }

    componentDidUpdate() {
      // do not call here the checkLogged method otherwise you could trigger an infinite loop
      this.checkIsNotLogged();
    }

    render() {
      if (this.state.loaded) {
        if (this.state.confirm) {
          return (
            <AuthComponent
              history={this.props.history}
              confirm={this.state.confirm}
            />
          );
        } else {
          return null;
        }
      } else {
        return null;
      }
    }
  };

  return AuthWrapped;
}