React的高阶组件(HOC)

1. 概念

高阶组件和高阶函数的类似,使用函数接收一个组件,并返回一个组件。

function withList(WrapComponent) {
  return class extends Component {
    render() {
      return 
; } } };

高阶组件主要用作于逻辑的封装、拦截渲染、拦截生命周期:获取渲染性能,日志打点等,安按照实现方式可以分为属性代理和反向继承两种。

2. 属性代理

属性代理的作用:

  • 代理props
  • 条件渲染
  • 添加状态(state)
  • 封装一些通用的逻辑

2.1 代理props

function withList(WrapComponent) {
  const data = [{ id: '1', text: '测试1' }, { id: '2', text: '测试2' }, { id: '3', text: '测试3' }, { id: '4', text: '测试4' }, { id: '5', text: '测试5' }]
  return class extends Component {
    render() {
      return 
{this.props.data.length > 0 ? : {emptyText}}
; } } }; class List extends Component { render() { return (
    {this.props.data.map(item => { return
  • {item.text}
  • })}
) } }; export default withList(List);

2.2 条件渲染

function withList(WrapComponent, emptyText) {
  return class extends Component {
    render() {
      return 
{this.props.data.length>0 ? : {emptyText}}
; } } }; class List extends Component { render() { return (
    {this.props.data.map(item => { return
  • {item.text}
  • })}
) } }; export default withList(List,'暂无数据');

2.3 添加状态
利用这一点可以将非受控组件转为受控组件

import React, { Component } from 'react'

class Input extends Component {
  render() {
    return (
      
    )
  }
};

function withInput(WrapComponent) {
  return class extends Component {
    state = {
      value: this.props.value
    }

    onChange = (value) => {
      this.setState({ value });
    }

    render() {
      return ;
    }
  }
};

export default withInput(Input);

3. 反向继承

反向继承的作用

  • 拦截渲染
  • 代理props
  • 劫持生命周期函数
  • 操作state
  • 修改react树

3.1 拦截渲染

function withList(WrapComponent) {
  return class extends WrapComponent {
    render() {
      return 
通过反向继承拦截渲染 {super.render()}
; } } };

3.2 劫持生命周期

function withList(WrapComponent) {
  return class extends WrapComponent {
    componentDidMount(){
      if(super.componentDidMount){
        super.componentDidMount.apply(this);
      };
      console.log('拦截生命周期');
    }
    render() {
      return 
通过反向继承拦截渲染 {super.render()}
; } } };

3.3 操作state

import React, { Component } from 'react';

function withList(WrapComponent) {
  return class extends WrapComponent {
    constructor(props) {
      super(props);
      this.state.data = []; //将列表数据置空
    }
    render() {
      return 
{super.render()}
} } }; class List extends Component { state = { data: [{ id: '1', text: '测试1' }, { id: '2', text: '测试2' }, { id: '3', text: '测试3' }, { id: '4', text: '测试4' }, { id: '5', text: '测试5' }], } render() { return (
    {this.state.data.map(item => { return
  • {item.text}
  • })}
) } }; export default withList(List);

3.4 修改react树


import React, { Component } from 'react';

function withList(WrapComponent) {
  return class extends WrapComponent {
    render() {
      const tree = super.render();
      let newProps = { ...tree.props };
      if (tree.type === 'ul') {
        newProps.value = 'value';
      }
      return React.cloneElement(tree, newProps, newProps.children);
    }
  }
};

class List extends Component {
  render() {
    return (
      
    {this.props.data.map(item => { return
  • {item.text}
  • })}
) } }; export default withList(List);

3.5 记录渲染性能

function withTime(WrapComponent) {
  return class extends WrapComponent {

    constructor(props) {
      super(props);
      this.start = 0;
      this.end = 0
    }

    componentWillMount() {
      if (super.componentWillMount) {
        super.componentWillMount.call(this);
      };
      this.start = Date.now();
    }

    componentDidMount() {
      if (super.componentDidMount) {
        super.componentDidMount.call(this);
      };
      this.end = Date.now();
      console.log(`渲染的时间为:${(this.end - this.start) / 1000}秒`)
    }

    render() {
      return super.render();
    }
  }
};

4. 使用装饰器

4.1 安装和配置
首先执行npm run eject暴露出webpack配置,然后安装装饰器插件

yarn add  @babel/plugin-proposal-decoreators;

最后在package.json中的babel配置中添加一下配置然后重新项目

  "babel": {
    "presets": [
      "react-app"
    ],
    "plugins":[
      [
        "@babel/plugin-proposal-decorators",
        {"legacy":true}
      ]
    ]
  }

配置完之后如果有报红需要配置一下:
文件-> 首选项 -> 搜索 ExperimentalDecorators 勾选上之后红线就消失了

4.2 使用

@withList
class List extends Component {
  render() {
    return (
      
    {this.props.data.map(item => { return
  • {item.text}
  • })}
) } };

5.总结

  • 高阶组件的作用有代复用、代理属性、拦截渲染、劫持生命周期
  • 反向继承能直接操作和拦截组件的state和生命周期,功能比属性代理更加强大

你可能感兴趣的:(前端,react,react.js,javascript,前端)