高阶组件(HOC)是react中对组件逻辑进行重用的高级技术。但高阶组件本身并不是React API。它只是一种模式,这种模式是由react自身的组合性质必然产生的。具体而言,高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。新组件承受业务逻辑,并将数据传入给接收的组件,接收的组件变成UI组件,只负责使用数据,而生成的新组件称为容器组件。
原来react使用混入(mixins)技术来解决交叉问题,但是react意识到混入(mixins)技术产生的问题要比带来的价值大(react为何移除mixins 这篇博文可以看下),所以也就有了高阶组件来解决交叉问题。
下面通过一个小demo来看一下高阶组建的应用。
数据和一些方法:
//数据和一些方法
const Datasource = {
data: { // 存放数据
comments: [
{id: 1, title: '今天是个好日子'},
{id: 2, title: '心想的事儿都能成'}
],
blogPost: [
{id: 1, title: '床前明月光'},
{id: 2, title: '疑是地上霜'},
]
},
getComments () {
return this.data.comments
},
getBlogPost () {
return this.data.blogPost
},
handlers: [],
addChangeListener (handler) {
this.handlers.push(handler)
},
removeChangeListener (handler) {
this.handlers = this.handlers.filter(item => item !== handler)
},
changeComments () {
this.data.comments.push({ id: 3, title: '今个老百姓真开心' })
this.emit()
},
changeBlogPost () {
this.data.blogPost.push({ id: 3, title: '举头望明月' })
this.emit()
},
emit () {
this.handlers.forEach(handler => handler())
}
}
UI组件1(木偶组件)
//UI组件 木偶组件
class CommentList extends Component {
render () {
return (
<div>
<h2>CommentList</h2>
<ul className = "list-group">
{
this.props.lists.map(item => <li key = {item.id}
className="list-group-item">{item.title}</li>)
}
</ul>
</div>
)
}
}
// 负责数据的逻辑处理,将其传递给UI组件, 此为容器组件 智能组件
const Container = higherOrderComponent(CommentList, () => Datasource.getComments())
export default Container
UI组件2(木偶组件)
class BlogList extends Component {
render () {
return (
<div>
<h3>BlogtList</h3>
<ol className = "list-group">
{
this.props.lists.map(item => <li key = {item.id}
className="list-group-item">{item.title}</li>)
}
</ol>
</div>
)
}
}
export default higherOrderComponent(BlogList, () => Datasource.getBlogPost() )
高阶组件:
const higherOrderComponent = (UIComponent, handler) => {
return class extends Component {
constructor () {
super()
this.state = {
lists: handler()
}
this.handleChange = this.handleChange.bind(this)
}
componentDidMount () {
Datasource.addChangeListener(this.handleChange)
}
componentWillUnmount () {
Datasource.removeChangeListener(this.handleChange)
}
handleChange () {
this.setState({lists: handler()})
}
render () {
return <UIComponent {...this.state}/>
}
}
}
export default higherOrderComponent
父组件:
class HocExample extends Component {
render () {
return (
<div>
<button onClick = { Datasource.changeComments }>change comments</button>
<CommentList/>
<BlogPost/>
</div>
)
}
}
简要讲解:
- 挂载组件时, 向
DataSource
添加一个监听函数。- 在监听函数内, 每当数据源发生变化,都是调用
setState
函数设置新数据。- 卸载组件时, 移除监听函数。