React 高阶组件 HOC

基本概念

在javascript中,高阶函数是以函数为参数,并返回值也是函数的函数。类似,高阶函数接受React组件作为参数,并且返回一个新的React组件。高阶组件本质上也是一个函数。
形式:

const EnhancedComponent = heigherComponent(WrappedComponent)

使用场景

1. 操作props,添加,删除,修改

在被包装组件接受props前。高阶组件可以先拦截props,对其添加,删除,修改。

// App.js
import React, { Component } from 'react';
import { MyComponentWithPersistenData } from './Children'
class App extends Component {
  constructor(props) {
    super(props)

    this.state = {
    }
  }
  render() {
    return (
      <div>
        <MyComponentWithPersistenData></MyComponentWithPersistenData>
      </div>
    );
  }
}

export default App;
// Children

import React, { Component } from 'react'

function withPersistenData(WrappedComponent){
    return  class Children extends Component {
        componentWillMount(){
            let data = 0;
            this.setState({
                data
            })
        }
        render() {
          return (
            <WrappedComponent {...this.props} data={this.state.data}></WrappedComponent>
          )
        }
      }
}
class MyComponent extends Component{
    render(){
        return <div>
                   {this.props.data}
               </div>
    }
}
export const MyComponentWithPersistenData = withPersistenData(MyComponent)

2. 通过ref访问组件实例

高阶组件通过ref获取被包装组件实例的引用,然后高阶组件就具备了直接操作被包装组件的方法和属性。但实际项目很少。

// App
import { MyComponentWithPersistenData , MyComponentWithref  } from './Children'

<MyComponentWithref></MyComponentWithref>

// Children
function Withref(WrappedComponent){
    return class extends React.Component{
        constructor(props) {
          super(props)
        
          this.state = {
             
          }
        }
        componentDidMount(){
            this.refs.wrap.handle()
        }
        render(){
            return <WrappedComponent ref="wrap" {...this.props}></WrappedComponent>
        }
    }
}
class MyComponent2 extends Component{
    handle = ()=>{
        alert("方法调用")
    }
    render(){
        return <div>
                   <button onClick={this.handle}>按钮</button>
               </div>
    }
}
export const MyComponentWithref = Withref(MyComponent2)

点击会触发handle的方法,高阶组件刷新页面的时候,组件中也componentDidMount调用包裹组件的方法。

3. 组件状态提升

无状态组件更容易复用。高阶组件可以通过将被包装组件的状态和相应的状态处理方法提升到高阶组件自身内部实现被包装组件的无状态化。比如,受控组件中状态维护放在高阶组件中

// App
import { MyComponentWithPersistenData , MyComponentWithref ,MyComponentControl } from './Children'
<MyComponentControl></MyComponentControl>
// Children
function withControlState(WrappedComponent){
    return class extends React.Component {
        constructor(props) {
          super(props)
        
          this.state = {
             value:''
          }
        }
        handleChange=(e)=>{
            this.setState({
                value:e.target.value
            })
        }
        render(){
            const newProps = {
                controlProps:{
                    value:this.state.value,
                    onChange:this.handleChange
                }
            }
            return <WrappedComponent {...this.props} {...newProps}></WrappedComponent>
        }
    }
}
class ControlComponent extends React.Component{
    render(){
        return <div>
                <input type="text" {...this.props.controlProps}/>
                {this.props.controlProps.value}
        </div>
        
    }
}
export const MyComponentControl = withControlState(MyComponent3)

以上App.js和Children.js文件

  • App.js
import React, { Component } from 'react';
import { MyComponentWithPersistenData , MyComponentWithref ,MyComponentControl } from './Children'
class App extends Component {
  constructor(props) {
    super(props)

    this.state = {
    }
  }
  render() {
    return (
      <div>
        <MyComponentWithPersistenData></MyComponentWithPersistenData>
        <MyComponentWithref></MyComponentWithref>
        <MyComponentControl></MyComponentControl>
      </div>
    );
  }
}

export default App;

  • Children.js
import React, { Component } from 'react'

function withPersistenData(WrappedComponent){
    return  class Children extends Component {
        componentWillMount(){
            let data = 0;
            this.setState({
                data
            })
        }
        render() {
          return (
            <WrappedComponent {...this.props} data={this.state.data}></WrappedComponent>
          )
        }
      }
}
function Withref(WrappedComponent){
    return class extends React.Component{
        constructor(props) {
          super(props)
        
          this.state = {
             
          }
        }
        componentDidMount(){
            this.refs.wrap.handle()
        }
        render(){
            return <WrappedComponent ref="wrap" {...this.props}></WrappedComponent>
        }
    }
}
function withControlState(WrappedComponent){
    return class extends React.Component {
        constructor(props) {
          super(props)
        
          this.state = {
             value:''
          }
        }
        handleChange=(e)=>{
            this.setState({
                value:e.target.value
            })
        }
        render(){
            const newProps = {
                controlProps:{
                    value:this.state.value,
                    onChange:this.handleChange
                }
            }
            return <WrappedComponent {...this.props} {...newProps}></WrappedComponent>
        }
    }
}
class MyComponent extends Component{
    render(){
        return <div>
                   {this.props.data}
               </div>
    }
}
class MyComponent2 extends Component{
    handle = ()=>{
        alert("方法调用")
    }
    render(){
        return <div>
                   <button onClick={this.handle}>按钮</button>
               </div>
    }
}
class MyComponent3 extends React.Component{
    render(){
        return <div>
                <input type="text" {...this.props.controlProps}/>
                {this.props.controlProps.value}
        </div>
        
    }
}
export const MyComponentWithPersistenData = withPersistenData(MyComponent)

export const MyComponentWithref = Withref(MyComponent2)

export const MyComponentControl = withControlState(MyComponent3)

4. 用其他元素包装

只是在高级组件中外面嵌套一个div,加css样式,布局。这个就不演示了。

如有问题,望斧正

猜你喜欢

转载自blog.csdn.net/weixin_44420276/article/details/86628747