# 完全理解高阶组件

# 高阶组件定义

a higher-order component is a function that takes a component and returns a new component.

翻译:高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件

理解了吗?看了定义似懂非懂?继续往下看。

# 函数模拟高阶组件

我们通过普通函数来理解什么是高阶组件。

  1. 最普通的方法,一个welcome,一个goodbye。两个函数先从localStorage读取了username,然后对username做了一些处理。

    function welcome() {
      const username = localStorage.getItem('username');
      console.log('welcome ' + username);
    }
    
    function goodbye() {
      const username = localStorage.getItem('username');
      console.log('goodbye ' + username);
    }
    
    welcome();
    goodbye();
    
  2. 我们发现两个函数有一句代码是一样的,这叫冗余唉。不好不好~(你可以把那一句代码理解成平时的一大推代码)

    我们要写一个中间函数,读取username,他来负责把username传递给两个函数。

    function welcome(username) {
      console.log('welcome ' + username);
    }
    
    function goodbye(username) {
      console.log('goodbye ' + username);
    }
    
    function wrapWithUsername(wrappedFunc) {
      const newFunc = () => {
        const uesrname = localStorage.getItem('username');
        wrappendFunc(username);
      };
    }
    
    welcome();
    goodbye();
    

好了,我们里面的wrapWithUsername函数就是一个"高阶函数"。

他做了什么?他帮我们处理了username,传递给目标函数。我们调用最终的函数welcome的时候,根本不用关心username是怎么来的。

我们增加个用户study函数。

function study(username) {
  console.log(username + ' study');
}
study = wrapWithUsername(study);

study();

这里你是不是理解了为什么说wrapWithUsername是高阶函数?我们只需要知道,用wrapWithUsername包装我们的study函数后,study函数第一个参数是username

我们写平时代码的时候,不用关心wrapWithUsername内部是如何实现的。

# 高阶组件

# 高阶组件就是一个没有副作用的纯函数

最普通的组件

welcome函数转为react组件。

import React, {Component} from 'react';

class Welcome extends Component {
  constructor(props) {
    super(props);
    this.state = {
      username: ''
    };
  }
  
  componentWillMount() {
    const uesrname = localStorage.getItem('username');
    this.setState({username});
  }
  
  render() {
    return (
      <div>welcome {this.state.uesrname}</div>
    );
  }
}

export default Welcome;

goodbye函数转为react组件。

import React, {Component} from 'react';

class Goodbye extends Component {
  constructor(props) {
    super(props);
    this.state = {
      username: ''
    }
  }
  
  componentWillMount() {
    const username = localStorage.getItem('username');
    this.setState({username});
  }
  
  render() {
    return (
      <div>goodbye {this.state.username}</div>
    );
  }
}

export default Goodbye;

现在你是不是看到问题所在了?两个组件大部分代码都是重复的。

按照上一节wrapWithUsername函数的思路,我们来写一个高阶组件(高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件)。

import React, {Component} from 'react';

export default WrappendComponent => {
  class NewComonent extend Component {
    constructor() {
      super();
      this.state = {
        username: ''
      };
    }
    
    componentWillMount() {
      const username = localStorage.getItem('username');
      this.setState({username});
    }
    
    render() {
      return <WrappendComponent username={this.state.username} />
    }
  }
    
  return NewComponent;
}

这样我们就能简化Welcome组件和Goodbye组件。

import React, {Component} from 'react';
import wrapWithUsername from './wrapWithUsername';

class Welcome extends Component {
  render() {
    return (
      <div>welcome {this.props.username}</div>
    );
  }
}

export default wrapWithUsername(Welcome);
import React, {Component} from 'react';
import wrapWithUsername from './wrapWithUsername';

class Goodbye extends Component {
  render() {
    return (
      <div>goodbye {this.props.username}</div>
    );
  }
}

export default wrapWithUsername(Goodbye);

看到没有,高阶组件就是把username通过props传递给目标组件了。目标组件只管从props里面拿来用就好了。

到这里位置,高阶组件就讲完了。你再返回去理解下定义,是不是豁然开朗~

你现在再来理解react-reduxconnect函数~

reduxstateaction创建函数,通过props注入给了Component。你在目标组件Component里面可以直接用this.props去调用redux stateaction创建函数了。

因此你可以在目标组件Component里面可以直接用this.props去调用redux stateaction创建函数了。

ConnectedComment = connect(mapStateToProps, mapDispatchToProps)(Component);

相当于这样

// connect是一个返回函数的函数(就是个高阶函数)
const enhance = connect(mapStateToProps, mapDispatchToProps);
// 返回的函数就是一个高阶组件,该高阶组件返回一个与Redux store关联起来的新组件
const ConnectedComment = enhance(Component);

antd的Form也是一样的

const WrappedNormalLoginForm = Form.craete()(NormalLoginForm);

# 现状

学习了高阶组件可以更好的理解很多React库的源码,但是实战中目前更推荐使用React Hooks。

React Hooks的出现,能够基本代替高阶函数的功能并且有更多优势,所以推荐学习React Hooks。

最近更新时间: 2020/5/26 19:03:58