高级组件HOC

91 阅读2分钟

⾼阶组件—HOC(Higher-Order Components)

  • ⾼阶组件是为了提⾼组件的复⽤率⽽出现的,抽离出具有相同逻辑 或相同展示的组件
  • ⾼阶组件其实是⼀个函数,接收⼀个组件,然后返回⼀个新的组件,返回的这个新的组件可以对属性进⾏包装,也可以重写部分⽣命周期
  • 例:
    // 高阶组件,接收⼀个组件,返回⼀个新的组件
    const withHOC = (Comp) => {
      const newComponent = (props) => {
        return <Comp {...props} name='Steven Wong' />;
      };
      return newComponent;
    };
    
    class HOC extends Component {
      render() {
        return (
          <div>
            <h1>{this.props.title}</h1>
            <p>{this.props.name}</p>
          </div>
        );
      }
    }
    
    export default withHOC(HOC);
    

⾼阶组件的链式调⽤

  • 编写⼀个⾼阶组件进⾏属性的添加
  • 编写⼀个⾼阶组件编写⽣命周期
  • 然后将以上两个⾼阶组件进⾏链式调⽤
  • 例:
    // 高阶组件,接收⼀个组件,返回⼀个新的组件
    const withHOC = (Comp) => {
      const newComponent = (props) => {
        return <Comp {...props} name='Steven Wong' />;
      };
      return newComponent;
    };
    
    // 高阶组件,重写生命周期,需要class组件返回class组件
    const withLifeCycle = (Comp) => {
      class newComponent extends Component {
        componentDidMount() {
          console.log('重写componentDidMount生命周期');
        }
        render() {
          return <Comp {...this.props} />;
        }
      }
      return newComponent;
    };
    
    class HOC extends Component {
      render() {
        return (
          <div>
            <h1>{this.props.title}</h1>
            <p>{this.props.name}</p>
          </div>
        );
      }
    }
    
    export default withLifeCycle(withHOC(HOC));
    

⾼阶组件装饰器写法

  • 由于⾼阶组件链式调⽤的写法看起来⽐较的麻烦也不好理解。逻辑会看的⽐较绕
  • ES7中就出现了装饰器的语法,专⻔拿来处理这种问题的
  • 安装⽀持装饰器语法的babel编译插件
    npm install --save-dev @babel/plugin-proposal-decorators
    
  • 配置⽂件
    • 更改我们的启动插件,引⼊ react-app-rewired 并修改 package.json ⾥的启动配置。由于新的 react-app-rewired@2.x 版本的关系,你还需要安装 customize-cra。
      yarn add react-app-rewired customize-cra
      
    • 更改package.json⽂件
      /* package.json -代表没改前的代码,+代表已经更改的代码*/
      "scripts": { 
      -  "start": "react-scripts start", 
      +  "start": "react-app-rewired start", 
      -  "build": "react-scripts build", 
      +  "build": "react-app-rewired build", 
      -  "test": "react-scripts test", 
      +  "test": "react-app-rewired test", 
      }
      
    • 然后在项⽬根⽬录创建⼀个 config-overrides.js ⽤于修改默认配置
      const { override, addBabelPlugins } = require('customize-cra');
      
      module.exports = override(
        addBabelPlugins(
          [
            '@babel/plugin-proposal-decorators',
            {
              legacy: true,
            },
          ]
        )
      );
      
    • 执⾏安装 babel-plugin-import插件
      yarn add babel-plugin-import
      
  • 重启项目
    @withHOC
    @withLifeCycle
    class HOC extends Component {
      render() {
        return (
          <div>
            <h1>{this.props.title}</h1>
            <p>{this.props.name}</p>
          </div>
        );
      }
    }
    
    // 装饰器写法
    export default HOC;
    // export default withLifeCycle(withHOC(HOC));
    

组件通信之上下⽂(context)

使⽤context可以避免通过中间元素传递props,context的设计⽬ 的是为了共享对于⼀个组件树⽽⾔是“全局”的数据,上下⽂context有两个⻆⾊

  • Provider 数据提供
  • Consumer 数据读取
import React, { Component } from 'react';

const myContext = React.createContext();
const { Provider, Consumer } = myContext;

const store = {
  name: 'Steven Wong',
  sex: '男',
};

const Son = (props) => {
  return (
    <Consumer>
      {(store) => (
        <div>
          <h1>{store.name}</h1>
          <p>{store.sex}</p>
        </div>
      )}
    </Consumer>
  );
};

const Father = (props) => {
  return <Son />;
};

class Context extends Component {
  render() {
    return (
      <Provider value={store}>
        <Father />
      </Provider>
    );
  }
}

export default Context;