Description
助你完全理解React高阶组件(Higher-Order Components)
有时候人们很喜欢造一些名字很吓人的名词,让人一听这个名词就觉得自己不可能学会,从而让人望而却步。但是其实这些名词背后所代表的东西其实很简单。来自React.js 小书
高阶组件定义
a higher-order component is a function that takes a component and returns a new component.
翻译:高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。
理解了吗?看了定义似懂非懂?继续往下看。
函数模拟高阶组件
我们通过普通函数来理解什么是高阶组件哦~
- 最普通的方法,一个
welcome
,一个goodbye
。两个函数先从localStorage
读取了username
,然后对username
做了一些处理。
function welcome() {
let username = localStorage.getItem('username');
console.log('welcome ' + username);
}
function goodbey() {
let username = localStorage.getItem('username');
console.log('goodbey ' + username);
}
welcome();
goodbey();
-
我们发现两个函数有一句代码是一样的,这叫冗余唉。不好不好~(你可以把那一句代码理解成平时的一大堆代码)
我们要写一个中间函数,读取
username
,他来负责把username
传递给两个函数。
function welcome(username) {
console.log('welcome ' + username);
}
function goodbey(username) {
console.log('goodbey ' + username);
}
function wrapWithUsername(wrappedFunc) {
let newFunc = () => {
let username = localStorage.getItem('username');
wrappedFunc(username);
};
return newFunc;
}
welcome = wrapWithUsername(welcome);
goodbey = wrapWithUsername(goodbey);
welcome();
goodbey();
好了,我们里面的wrapWithUsername
函数就是一个“高阶函数”。
他做了什么?他帮我们处理了username
,传递给目标函数。我们调用最终的函数welcome
的时候,根本不用关心username
是怎么来的。
我们增加个用户study
函数。
function study(username){
console.log(username+' study');
}
study = wrapWithUsername(study);
study();
这里你是不是理解了为什么说wrapWithUsername
是高阶函数?我们只需要知道,用wrapWithUsername
包装我们的study
函数后,study
函数第一个参数是username
。
我们写平时写代码的时候,不用关心wrapWithUsername
内部是如何实现的。
高阶组件
高阶组件就是一个没有副作用的纯函数。
我们把上一节的函数统统改成react
组件。
- 最普通的组件哦。
welcome
函数转为react
组件。
import React, {Component} from 'react'
class Welcome extends Component {
constructor(props) {
super(props);
this.state = {
username: ''
}
}
componentWillMount() {
let username = localStorage.getItem('username');
this.setState({
username: username
})
}
render() {
return (
<div>welcome {this.state.username}</div>
)
}
}
export default Welcome;
goodbey
函数转为react
组件。
import React, {Component} from 'react'
class Goodbye extends Component {
constructor(props) {
super(props);
this.state = {
username: ''
}
}
componentWillMount() {
let username = localStorage.getItem('username');
this.setState({
username: username
})
}
render() {
return (
<div>goodbye {this.state.username}</div>
)
}
}
export default Goodbye;
- 现在你是不是更能看到问题所在了?两个组件大部分代码都是重复的唉。
按照上一节wrapWithUsername
函数的思路,我们来写一个高阶组件(高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件)。
import React, {Component} from 'react'
export default (WrappedComponent) => {
class NewComponent extends Component {
constructor() {
super();
this.state = {
username: ''
}
}
componentWillMount() {
let username = localStorage.getItem('username');
this.setState({
username: username
})
}
render() {
return <WrappedComponent 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>
)
}
}
Welcome = wrapWithUsername(Welcome);
export default Welcome;
import React, {Component} from 'react';
import wrapWithUsername from 'wrapWithUsername';
class Goodbye extends Component {
render() {
return (
<div>goodbye {this.props.username}</div>
)
}
}
Goodbye = wrapWithUsername(Goodbye);
export default Goodbye;
看到没有,高阶组件就是把username
通过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);
参考地址:
- http://huziketang.com/books/react/lesson28
- https://react.bootcss.com/react/docs/higher-order-components.html
❤️感谢大家
关注公众号「前端技术砖家」,拉你进交流群,大家一起共同交流和进步。
Activity
liujiusheng commentedon Jan 25, 2018
666.写这么详细。我今天才重构了我的第一篇文章。
yanlele commentedon Jan 26, 2018
写的非常的好
catgu commentedon Jan 29, 2018
写的好棒!一看就明白了,感谢感谢
winnieping commentedon Feb 5, 2018
好棒,我也来看啦
shesio commentedon Feb 22, 2018
受教了
KayneWang commentedon Feb 27, 2018
清晰易懂,感谢分享
jiangxtx commentedon Mar 14, 2018
讲解通俗易懂,满分!
LoveofRedMoon commentedon Mar 30, 2018
写的好棒~瞬间理解了
hu382337381 commentedon Apr 24, 2018
不错,通俗易懂
ly678910 commentedon Jul 2, 2018
讲的很赞
wangqiao66 commentedon Jul 17, 2018
666
24 remaining items