1. 什么是高阶组件
高阶组件是一个函数。传递给它一个组件,返回一个新的组件。
const EnhancedComponent = enhance( MyComponent )
enhance就是我们的高阶组件,在其中可以加入各种逻辑来增强我们的 MyComponent
2. 高阶组件的用途
3. 高阶组件的实现方式
反向继承 ( Inheritance Inversion )
4. 属性代理 ( Props Proxy )
const enhance = (WrapperComponent, key) => {
return class extends Component {
constructor () {
super()
this.state = { data: null }
}
componentWillMount () {
let data = localStorage.getItem(key)
this.setState({ data })
}
render() {
return <WrapperComponent {...this.props} data:{ this.state.data } />
}
}
}
class MyComponent extends Component {
render() {
return <div>
1. 操作props
<input value={this.props.data} />
</div>
}
}
export default enhance(MyComponent, 'locale')
高阶组件为被包裹组件
添加了data
属性,该属性的值为 localStorgae中key为locale
的值,通过传入不同的参数key, 可以起到为组件初始化属性的作用。
const enhance = (WrapperComponent) => {
return class extends Component {
getIns(ins) {
this.childIns = ins
// this.childIns.method()
}
render() {
return <WrapperComponent ref={(ins)=>{this.getIns(ins)}} />
}
}
}
class MyComponent extends Component {
render() {
return <div>
2. 获取 Refs 引用
</div>
}
}
export default enhance(MyComponent)
通过属性代理拿到被包裹组件
的实例引用this.childIns
,从而可以调用被包裹组件
实例上的方法。
const enhance = (WrapperComponent) => {
return class extends Component {
constructor(props){
super(props)
this.state = {
fields: {}
}
}
getField(fieldName) {
if (!this.state.fields[fieldName]) {
this.state.fields[fieldName] = {
value: '',
onChange: event => {
this.state.fields[fieldName].value = event.target.value
this.forceUpdate()
}
}
}
return {
value: this.state.fields[fieldName].value,
onChange: this.state.fields[fieldName].onChange
}
}
render() {
const props = Object.assign({}, this.props, {
fields: this.getField.bind(this),
})
return (
<WrapperComponent {...props}/>
)
}
}
}
class MyComponent extends Component {
render() {
return <form>
3. 抽象state, 受控组件
<input type="name" {...this.props.fields('name')}/>
</form>
}
}
export default enhance(MyComponent)
将被包裹组件
的state抽象为自身的props,并从高阶组件中获得。常见的例子就是实现不受控组件
到受控组件
的转变。 参考 antd form
组件的实现.
const withStyle = (WrapperComponent) => {
return class extends Component {
render() {
return <div style={{background:"blue", padding:'4px',borderRadius:'4px',color:'white'}}>
<WrapperComponent {...this.props} />
</div>
}
}
}
class MyComponent extends Component {
render() {
return <div>
4. 元素包裹, 进行布局或者统一样式
</div>
}
}
export default withStyle(MyComponent)
通过在外面包裹一个带有样式的组件作为父组件,从而达到布局或者设置样式的目的。
5. 反向继承 ( Inheritance Inversion )
const enhance = (WrapperComponent) => {
// 返回的组件继承传入的 WrapperComponent组件
return class extends WrapperComponent {
render() {
// 获取渲染的react元素树
let elementsTree = super.render();
const enhanceProps = {};
if(elementsTree && elementsTree.type === 'div') {
enhanceProps.style = { backgroundColor:'green' }
}
const props = Object.assign({}, elementsTree.props, enhanceProps)
elementsTree = React.cloneElement(elementsTree, props, elementsTree.props.children)
return elementsTree;
}
}
}
class MyComponent extends Component {
render() {
return <div>
5. 渲染劫持
</div>
}
}
export default enhance(MyComponent)
渲染劫持即通过反向继承,在返回elementsTree
之前,执行一些逻辑代码对elementsTree
进行修改。来改变最终渲染在页面的内容。
const enhance = (WrapperComponent) => {
return class extends WrapperComponent {
render() {
return (
<div>
<p>{this.state.text}</p>
{super.render()}
</div>
)
}
}
}
class MyComponent extends Component {
constructor(props){
super(props)
this.state = {
text: 'hi, i am wrapperComponent'
}
}
render() {
return <div>
7. 操作state {this.state.text}
</div>
}
}
export default enhance(MyComponent)
在enhance内部,可以访问修改删除被包裹组件
的 state。
6. 柯里化和高阶组件参数
6.1 柯里化
const funcA = (a) => {
return (b) => {
return a + b;
}
}
const addWith5 = funcA(5)
console.log(addWith5(1))
console.log(addWith5(2))
利用闭包,返回的函数addWith5
始终能访问到5
这个变量,通过这种方式分解函数的参数。
6.2 高阶组件参数
const enhance = (...params) => {
// 对参数params, 执行一些操作
return (WrapperComponent) => {
return class HOC extends Component {
render() {
return <WrapperComponent {...this.props} />;
}
}
}
}
例如 react-redux
中 connect的用法 connect(mapStateToProps,...)(WrapperComponent)
7. 链接
react高阶组件官方文档
React Higher Order Components in depth
张鑫旭 - JS中的柯里化
react.js 小书
高阶组件(HOC)-中文