高阶组件(Higher-Order Components)
http://huziketang.mangojuice.top/books/react/lesson28
高阶组件就是一个函数,传给它一个组件,它返回一个新的组件
高阶组件的作用是用于代码复用,可以把组件之间可复用的代码、逻辑抽离到高阶组件当中。新的组件和传入的组件通过 props 传递信息。
使用场景:
有类似的几个组件但是组件内部只有少部分是不同的,它们身上都还有一些公用的方法,并且这些少部分组件组件都还要调用大组件的方法或者访问它的一些数据
如果我们按照组件封装的方法来实现的的话,我们封装一个大组件,然后把不同的小组件传进去,然后通过props把方法传到小组件,通过回调触发,但是这里有一个问题,我们写这几个组件的时候每次都要把大组件写一遍然后把子组件嵌入进去。假如这里我们采用高阶组件来实现的话,我们只需要把公用的方法和数据写到高阶函数返回的组件中,然后把组件传进去就可以了,最后在每个调用这个大组件的地方直接调用这个函数就可以了。
实例:
wrapWithLoadData根据第二个参数 name 在挂载阶段从 LocalStorage 加载数据,并且 setState 到自己的 state.data 中,而渲染的时候将 state.data 通过 props.data 传给 WrappedComponent
import React, { Component } from 'react'
export default (WrappedComponent, name) => {
class wrapWithLoadData extends Component {
constructor () {
super()
this.state = { data: null }
}
componentWillMount ()
{ let data = localStorage.getItem(name)
this.setState({ data })
}
render () {
return
}
}
return wrapWithLoadData
}
调用:
import wrapWithLoadData from './wrapWithLoadData'
class InputWithUserName extends Component {
render ()
{ return }
}
InputWithUserName = wrapWithLoadData(InputWithUserName, 'username')
export default InputWithUserName
如果现在我们需要另外一个文本输入框组件,它也需要 LocalStorage 加载 'content' 字段的数据。我们只需要定义一个新的 TextareaWithContent:
import wrapWithLoadData from './wrapWithLoadData'
class TextareaWithContent extends Component {
render () {
return
} }
TextareaWithContent = wrapWithLoadData(TextareaWithContent, 'content')
export default TextareaWithContent
最终使用:
import InputWithUserName from './InputWithUserName'
import TextareaWithContent from './TextareaWithContent
class Index extends Component {
render () {
return (
)
} }
假设现在我们需求变化了,现在要的是通过 Ajax 加载数据而不是从 LocalStorage 加载数据。我们只需要新建一个 wrapWithAjaxData 高阶组件:
import React, { Component } from 'react'
export default (WrappedComponent, name) => {
class wrapWithAjaxData extends Component {
constructor ()
{ super()
this.state = { data: null }
}
componentWillMount () {
ajax.get('/data/' + name, (data) => {
this.setState({ data })
}) }
render () {
return
} }
return wrapWithAjaxData
}
其实就是改了一下 wrapWithLoadData 的 componentWillMount 中的逻辑,改成了从服务器加载数据。现在只需要把 InputWithUserName 稍微改一下:
import wrapWithAjaxData from './wrapWithAjaxData'
class InputWithUserName extends Component {
render () {
return
} }
InputWithUserName = wrapWithAjaxData(InputWithUserName, 'username')
export default InputWithUserName