Joyeuxman / Joyeuxman.github.io

个人博客
1 stars 0 forks source link

React 高阶组件 #11

Open Joyeuxman opened 5 years ago

Joyeuxman commented 5 years ago

概念

高阶函数:接受函数作为输入,输出另一个函数的一类函数。

高阶组件:通过包裹被传入的React组件,经过一系列处理,最终返回一个相对增强的React组件,供其它组件调用。

//声明高阶组件
高阶组件(低阶组件的配置信息){
    return 低阶组件 =>{
            return 低阶组件和低阶组件的配置信息的结合体
    }
}
//调用高阶组件
高阶组件(低阶组件的配置信息)(低阶组件)

高阶组件的使用场景

实现高阶组件的方式

属性代理(props-proxy)

属性代理:通过做一些操作,将被包裹组件(Demo)的props()和新生成的props一起传递给此组件。

示例:

function withHeader(WrappedComponent) {
  return class HOC extends React.Component {
    static defaultProps = {
      desc_1: '来自增强组价的desc,增加props方式一',
    }
    static displayName = `HOC(${getDisplayName(WrappedComponent)})`;
    constructor(props) {
      super(props);
      this.state = {
        name_0: "HOC",
      }
    }

    render() {
      console.dir(WrappedComponent);//f Demo(props)
      console.log('this===', this);//HOC-->this.props-->{desc_1:...}
      return (
        <div>
          <h3>标题</h3>
          <WrappedComponent {...this.props} enhance={'来自增强组件的enhance,增加props的方式二'} />
        </div>
      )
    }
  }
}

@withHeader
export default class Demo extends React.Component {
  static defaultProps = {
    desc_0: '来自包裹组件的desc',
  }
  constructor(props) {
    super(props);
    this.state = {
      name_1: 'Demo',
    }
  }
  render() {
    console.log('Demo this===', this);//Demo-->this.props-->{desc_0:...,desc_1:...,enhance:...}
    return (
      <div>
        我是一个普通组件
      </div>
    )
  }
}

总结:withHeader是一个高阶函数,接受Demo组件,返回一个增强的Demo组件。本示例中,增加了一个标题,同时,增强了属性。 在Demo组件类实例化后的this中,其props属性中含有desc_0(来自增强组件)、desc_1(来自包裹组件自身),当被包裹组件和增强组价的属性名称相同时,包裹组件的属性会覆盖掉增强组件的同名属性。

反向继承(inheritance inversion)

Joyeuxman commented 5 years ago

补充代码

var enhanceComponent = (Component) => {
      class Enhance extends React.Component {
        render() {
          return (
            <Component {...this.props} />
          )
        }
      }
    }

    var OriginalTitle = () => <h1>Hello World</h1>;
    var EnhancedTitle = enhanceComponent(OriginalTitle);

    class App extends React.Component {
      render() {
        return <EnhancedTitle />;
      }
    }

    // 高阶组件的主要功能主要是封装并抽离组件的通用逻辑
    function getDisplayName(component) {
      return component.displayName || component.name || 'Component';
    }
    export default function withHeader(title = 'title') {
      return function (WrappedComponent) {
        return class HOC extends React.Component {
          static displayName = `HOC(${getDisplayName(WrappedComponent)})`;
          render() {
            return (
              <div>
                <div>
                  {title}
                </div>
                <WrappedComponent {...this.props} />
              </div>
            )
          }
        }
      }
    }

    @withHeader('Demo')   //相当于 const enhanceDemo = withHeader('Demo')(Demo)
    export default class Demo extends React.Component {
      render() {
        return (
          <div>
            我是一个普通组件
          </div>
        )
      }
    }

    // 基于属性代理的方式
    // this 指向谁 HOC
    export default function withHeader(WrappedComponent) {
      return class Hoc extends React.Component {
        render() {
          const newProps = {
            test: 'hoc',
          }
          return (
            <WrappedComponent {...this.props} {...newProps} />
          )
        }
      }
    }

    // 基于反向继承的方式
    export default function (WrappedComponent) {
      return class Inheritance extends WrappedComponent {
        componentDidMount() {
          console.log(this.state);
        }
        render() {
          return super.render();
        }
      }
    }

    // 基于反向继承的方式实现一个loading组件
    import React, { Component } from 'react';
    import { spin } from 'antd';

    export default function withLoading(loadingCheck) {
      return function (WrappedComponent) {
        return class extends WrappedComponent {
          componentWillUpdate(nextProps, nextState) {
            console.log('更新之前');
          }
          render() {
            if (loadingCheck(this.props)) {
              return <Spin tip="加载中" size="large">
                {super.render()}
              </Spin>
            } else {
              return super.render();
            }
          }
        }
      }
    }

    // @withLoading(props => {
    //   return props.IndexStore.accountList.length === 0;
    // })

    // 基于属性代理的方式实现Copy高阶组件
    import React, { Component } from 'react';
    import ReactDom from 'react-dom';
    import { message } from 'antd';
    import gotem from 'gotem';

    export default copy = (targetName) => {
      return (WrappedComponent) =>{
        return class extends Component{
          componentDidMount(){
            const ctx = this;
            const dom = ReactDom.findDOMNOde(ctx);
            const nodes = {
              trigget:dom,
              target:dom.querySelect(targetName),
            }
            gotem(nodes.trigger,nodes.target,{
              success:function(){
                message.success('复制成功');
              },
              error:function(){
                message.error('复制失败,请手动输入');
              }
            })
          }
          render(){
            return(
              <WrappedComponent {...this.props} />
            )
          }
        }
      }
    }

    @copy('h3')
    class Info extends Component{
      render(){
        return(
          <div>
            <h3>
              阿西吧,点击复制文字
            </h3>
          </div>
        )
      }
    }