有时候人们很喜欢造一些名字很吓人的名词,让人一听这个名词就觉得自己不可能学会,从而让人望而却步。但是其实这些名词背后所代表的东西其实很简单。
我不能说高阶组件就是这么一个东西。但是它是一个概念上很简单,但却非常常用、实用的东西,被大量 React.js 相关的第三方库频繁地使用。在前端的业务开发当中,你不掌握高阶组件其实也可以完成项目的开发,但是如果你能够灵活地使用高阶组件,可以让你代码更加优雅,复用性、灵活性更强。它是一个加分项,而且加的分还不少。
高阶组件是一个函数(而不是组件),它接受一个组件作为参数,返回一个新的组件。这个新的组件会使用你传给它的组件作为子组件 -引用自React.js小书
我希望通过自己的理解,然后把一些本来就简单但是被说复杂的东西,通过自己的语言去把它通俗易懂地说出来,毕竟我也是俗人一个,俗人讲俗话最容易懂了不是吗?
那么根据这里的定义,我们先写两个函数来进行举栗子:
//比如我们写个函数,实现去冰箱拿牛奶,我们先要打开冰箱才能拿到牛奶,假如localstorage就是冰箱,牛奶这个变量就存在里面,那么我们可以这么写 function want(){ let milk=window.localstorage.getItem('milk'); console.log('I want'+orange) } //比如我们写个函数,实现又去冰箱拿牛奶喝,我们先要打开冰箱才能拿到牛奶,假如localstorage就是冰箱,牛奶这个变量就存在里面,那么我们可以这么写 function drink(){ let milk=window.localstorage.getItem('milk'); console.log('I drink'+milk) }
每次我们都要去打开冰箱去重复这个动作,是不是很烦,所以我们要进行优化,我们只要告诉某个函数,说我们要拿牛奶,怎么拿我不管,拿到之后我可以进行任意操作。
//首先我们先对原本的函数进行优化 function want(milk){ console.log('I want'+orange) } //比如我们写个函数,实现又去冰箱拿牛奶喝,我们先要打开冰箱才能拿到牛奶,假如localstorage就是冰箱,牛奶这个变量就存在里面,那么我们可以这么写 function drink(milk){ console.log('I drink'+milk) } function wrapWithMilk(withAction){ let newAction=()=>{ let milk=window.localstorage.getItem('milk'); withAction(milk); } return newAction; } want=wrapWithMilk(want); drink=wrapWithMilk(drink); want(); drink(); //这里wrapWithMilk就是我们所说的高阶函数了,我们只需要知道want跟drink的第一个参数是milk就行,怎么拿到的我们都不用去管啦 接下来说说高阶组件 其实高阶组件就是一个没有副作用的纯函数 我们将函数转换为reat组件试下 import React, {Component} from 'react' class Want extends Component { constructor(props) { super(props); this.state = { milk: '' } } componentWillMount() { let milk= localStorage.getItem('milk'); this.setState({ milk: milk }) } render() { return ( <div>I want {this.state.milk}</div> ) } export default Want; } -------------------------------------------------------- class Drink extends Component { constructor(props) { super(props); this.state = { milk: '' } } componentWillMount() { let milk= localStorage.getItem('milk'); this.setState({ milk: milk }) } render() { return ( <div>I drink{this.state.milk}</div> ) } export default Drink; }
两个组件大部分代码都是重复的唉。
按照上一节wrapWithMilk函数的思路,我们来写一个高阶组件(高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件)。
import React, {Component} from 'react' export default (WrappedComponent) => { class NewComponent extends Component { constructor() { super(); this.state = { milk: '' } } componentWillMount() { let milk= localStorage.getItem('milk'); this.setState({ milk: milk }) } render() { return <WrappedComponent&rt; username={this.state.milk}/&rt; } } return NewComponent } //然后我们来去简化我们的Want跟Drink组件 class Want extends Component { render() { return ( <div>I want {this.props.milk}</div> ) } export default Want; } -------------------------------------------------- class Drink extends Component { render() { return ( <div>I drink{this.props.milk}</div> ) } export default Drink; } 然后我们调用高阶组件去改造它 import React, {Component} from 'react'; import wrapWithMilk from 'wrapWithMilk'; class Want extends Component { render() { return ( <div&rt;I want{this.props.milk} <div&rt; ) } } Welcome = wrapWithUsername(Want); export default Want; -------------------------------------------------------------------------------- import React, {Component} from 'react'; import wrapWithMilk from 'wrapWithMilk'; class Drink extends Component { render() { return ( <div&rt;I drink {this.props.milk} <div&rt; ) } } Welcome = wrapWithUsername(Drink); export default Drink;
高阶组件就是把milk通过props传递给目标组件了。目标组件只管从props里面拿来用就好了。
现在可以理解react-redux的connect函数了~
把redux的state和action创建函数,通过props注入给了Component。
你在目标组件Component里面可以直接用this.props去调用redux state和action创建函数了。
ConnectedComment = connect(mapStateToProps, mapDispatchToProps)(Component); // connect是一个返回函数的函数(就是个高阶函数) const enhance = connect(mapStateToProps, mapDispatchToProps); // 返回的函数就是一个高阶组件,该高阶组件返回一个与Redux store 关联起来的新组件 const ConnectedComment = enhance(Component); antd的Form也是一样的 const WrappedNormalLoginForm = Form.create()(NormalLoginForm);