# 完全理解高阶组件
# 高阶组件定义
a higher-order component is a function that takes a component and returns a new component.
翻译:高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。
理解了吗?看了定义似懂非懂?继续往下看。
# 函数模拟高阶组件
我们通过普通函数来理解什么是高阶组件。
最普通的方法,一个
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();
我们发现两个函数有一句代码是一样的,这叫冗余唉。不好不好~(你可以把那一句代码理解成平时的一大推代码)
我们要写一个中间函数,读取
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-redux
的connect
函数~
把redux
的state
和action
创建函数,通过props
注入给了Component
。你在目标组件Component
里面可以直接用this.props
去调用redux state
和action
创建函数了。
因此你可以在目标组件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.craete()(NormalLoginForm);
# 现状
学习了高阶组件可以更好的理解很多React库的源码,但是实战中目前更推荐使用React Hooks。
React Hooks的出现,能够基本代替高阶函数的功能并且有更多优势,所以推荐学习React Hooks。
← 总结 React Hooks →