高阶组件(HOC)是React开发中的特有名词,一个函数返回一个React组件,指的就是一个React组包裹着另一个React组件。可以理解为一个生产React组件的工厂。
有两种类型的HOC:
- Props Proxy(pp) HOC对被包裹组件
WrappedComponent
的props进行操作。 - Inherbitance Inversion(ii)HOC继承被包裹组件
WrappedComponent
。
Props Proxy
一种最简单的Props Proxy实现
function ppHOC(WrappedComponent) { return class PP extends React.Component { render() { return <WrappedComponent {...this.props}/> } } }
这里的HOC是一个方法,接受一个WrappedComponent
作为方法的参数,返回一个PP class,renderWrappedComponent
。使用的时候:
const ListHOCInstance = ppHOC(List) <ListHOCInstance name='instance' type='hoc' />
这个例子中,我们将本应该传给List
的props,传给了ppHoc返回的ListHOCInstance
(PP)上,在HOC内部我们将PP的参数直接传给List
(WrappedComponent
)。这样的就相当于在List
外面加了一层代理,这个代理用于处理即将传给WrappedComponent
的props,这也是这种HOC为什么叫Props Proxy。
在pp中,我们可以对WrappedComponent
进行以下操作:
- 操作props(增删改)
- 通过refs访问到组件实例
- 提取state
- 用其他元素包裹
WrappedComponent
操作props
比如添加新的props给WrappedComponent
:
const isLogin = false; function ppHOC(WrappedComponent) { return class PP extends React.Component { render() { const newProps = { isNew: true,login: isLogin } return <WrappedComponent {...this.props} {...newProps}/> } } }
WrappedComponent
组件新增了两个props:isNew和login。
通过refs访问到组件实例
function refsHOC(WrappedComponent) { return class RefsHOC extends React.Component { proc(wrappedComponentInstance) { wrappedComponentInstance.method() } render() { const props = Object.assign({},this.props,{ref: this.proc.bind(this)}) return <WrappedComponent {...props}/> } } }
Ref 的回调函数会在 WrappedComponent
渲染时执行,你就可以得到WrappedComponent
的引用。这可以用来读取/添加实例的 props ,调用实例的方法。
不过这里有个问题,如果WrappedComponent
是个无状态组件,则在proc中的wrappedComponentInstance
是null,因为无状态组件没有this,不支持ref。
提取state
你可以通过传入 props 和回调函数把 state 提取出来,
function ppHOC(WrappedComponent) { return class PP extends React.Component { constructor(props) { super(props) this.state = { name: '' } this.onNameChange = this.onNameChange.bind(this) } onNameChange(event) { this.setState({ name: event.target.value }) } render() { const newProps = { name: { value: this.state.name,onChange: this.onNameChange } } return <WrappedComponent {...this.props} {...newProps}/> } } }
使用的时候:
class Test extends React.Component { render () { return ( <input name="name" {...this.props.name}/> ); } } export default ppHOC(Test);
这样的话,就可以实现将input转化成受控组件。
用其他元素包裹 WrappedComponent
这个比较好理解,就是将WrappedComponent组件外面包一层需要的嵌套结构
function ppHOC(WrappedComponent) { return class PP extends React.Component { render() { return ( <div style={{display: 'block'}}> <WrappedComponent {...this.props}/> </div> ) } } }
Inheritance Inversion(反向继承)
先看一个反向继承(ii)的