HOC

144 阅读1分钟

什么是hoc

hoc本质一个函数,接收一个组件返回一个组件

自定义hoc

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

export function withUser(InnerComponent){
    return function OuterComponent (props){
        let userInfo = localStorage.getItem('userInfo');
        try{
            userInfo = JSON.parse(userInfo) || {}
        }catch(err){
            userInfo = {}
        } 
        return (
            <InnerComponent user={userInfo} {...props} />
        )
    }
}

export function withStorage(...keys){
    // 返回值才是高阶组件
    return function withData(InnerComponent){
        // {token:xxx,current:10}
        const provide = keys.reduce((prev,key)=>{
            let data = localStorage.getItem(key);
            try{
                data = JSON.parse(data)
            }catch(err){
                data = data;
            }

            prev[key] = data
            return prev;
        },{});

        return class OuterComponent extends React.Component{
            render(){
                return (
                    <InnerComponent {...provide} {...this.props} ></InnerComponent>
                )

            }
        }
    }
}

反向继承 (只适用于类组件,可以拦截生命周期钩子)

export function withAuth(InnerComponent){
    class OuterComponent extends InnerComponent{
        render(){
            console.log('Outer.render');
            if(this.props.user.username){
                return super.render()
            }else{
                return <Redirect to="/login" />
            }
        }
    }

    OuterComponent = withUser(OuterComponent)
    return OuterComponent;
}
// 用户登录权限控制
export function withAuth(InnerComponent){
    @withUser
    class OuterComponent extends React.Component{
        render(){
            if(this.props.user.username){
                return <InnerComponent {...this.props} />
            }else{
                return <Redirect to="/login" />
            }
        }
    }

    // OuterComponent = withUser(OuterComponent)
    return OuterComponent;
}

当然也可在自定义的hoc中使用 react-redux

hoc 代码
import getToken from "./getToken";
import { connect } from "react-redux";
import { loginAction } from "../redux/actions";

// 反向继承
export function withAuth(InnerComponent) {
  class OuterComponent extends InnerComponent {
    state = {
      loginInfo: {}
    };
    componentDidMount() {
      console.log("hoc didMount", this.props);
      // super.componentDidMount();
      this.getToken();
    }
    // 获取token
    getToken = async () => {
      const { token, client } = await getToken();
      console.log("token, client", token, client);
      let loginInfo = { token, client };
      if (token) {
        // super.componentDidMount();
        this.setState({
          loginInfo
        });
      }
      this.props.login(loginInfo);
    };
    render() {
      // console.log("this.state.loginInfo", this.state.loginInfo);
      if (this.state.loginInfo.token) {
        super.componentDidMount();
      }

      return (
        <InnerComponent {...this.props} loginInfo={this.state.loginInfo} />
      );
    }
  }
  // 映射状态
  const mapStateToProps = (state) => {
    console.log(state);
  };

  // 映射操作状态的方法
  // mapDispatchToProps的简写
  const mapDispatchToProps = {
    login: loginAction
  };
  OuterComponent = connect(mapStateToProps, mapDispatchToProps)(OuterComponent);
  return OuterComponent;
}
组件代码
import React from "react";
import { connect } from "react-redux";
import { withAuth } from "../utils/hoc";
import { loginAction } from "../redux/actions";

class TestUI extends React.Component {
  componentDidMount() {
    console.log("test DidMount");
    this.getLoginInfo();
  }
  getLoginInfo = (loginInfo) => {
    console.log("获取登录信息", this.props, loginInfo);
    console.log("获取登录信息,this.props", this.props);
  };

  render() {
    console.log("test render", this.props);

    return <div>我是Test组件</div>;
  }
}
const Test2 = withAuth(TestUI);
// 映射状态
const mapStateToProps = (state) => {
  console.log("state========", state);
  return { lognObj: state };
};

// 映射操作状态的方法
// mapDispatchToProps的简写
const mapDispatchToProps = {};
const Test = connect(mapStateToProps, mapDispatchToProps)(Test2);

export default Test;