如何更新高阶组件

问题描述 投票:-1回答:2

我在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 }
]

创建了HOC withAuth,当用户未记录时,它应返回到父路由。当我要去路线(因为没有记录) - 它的确定和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;
}
javascript reactjs react-router
2个回答
1
投票

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

在你的情况下,你有一个可以改变的Auth状态,当loggedIn状态改变时,一切都应该重新渲染。正确的方法是使用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,因为它使用了反应中的Context API。

希望这对你有所帮助! :)


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;
}
© www.soinside.com 2019 - 2024. All rights reserved.