• React高阶组件详解


    高阶组件是什么?

    高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。

    高阶组件是参数为组件,返回值为新组件的函数

    在此期间,我们可以对该组件进行props处理,事件处理等工作
    
    • 1

    认识高阶组件

    1. 复用逻辑

      对组件进行加工处理,根据需求来定制专属化的HOC

    2. 强化props

      劫持上一层传过来的props,混入新的props

    3. 赋能组件

      HOC有一项独特的特性,就是可以给被HOC包裹的业务组件,提供一些拓展功能,比如说额外的生命周期,额外的事件,但是这种HOC,可能需要和业务组件紧密结合

    4. 控制渲染

      劫持渲染是hoc一个特性,在wrapComponent包装组件中,可以对原来的组件,进行条件渲染,节流渲染,懒加载等功能

    使用方式

    • 装饰器模式

    • 函数包裹

    两种不同的高阶组件

    • 正向的属性代理

        function HOC(WrapComponent){
          return class Advance extends React.Component{
            state={
                name:'loong'
            }
            render(){
                return <WrapComponent  { ...this.props } { ...this.state }  />
            }
          }
        }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

      我们来看一下上面这个例子,return 返回结果是父组件(代理组件)对子组件(业务组件)的一系列操作

      在 fiber tree上,先mounted组件,然后才是我们的业务组件

    • 反向的组件继承

          class Index extends React.Component{
              render(){
                  return <div> hello,world  </div>
              }
          }
          function HOC(Component){
              return class wrapComponent extends Component{
      
              }
          }
          export default HOC(Index) 
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      HOC采用继承的方式, 代理组件继承了业务组件的本身,我们在使用的时候直接实例化代理组件HOC即可

    编写高阶组件

    很多文章对其有很多分类,我这里就按照我的理解去分类
    
    • 1
    1. 增强props
      混入props 代理组件state状态会混入(上面有混入的例子), 初次之外我们还可以进行控制state的更新

      function classHOC(WrapComponent){
          return class  Idex extends React.Component{
              constructor(){
                  super()
                  this.state={
                      name:'alien'
                  }
              }
              changeName(name){
                  this.setState({ name })
              }
              render(){
                  return <WrapComponent { ...this.props }  { ...this.state } changeName={this.changeName.bind(this)  }  />
              }
          }
      }
      function Index(props){
          const [ value ,setValue ] = useState(null)
          const { name ,changeName } = props
          return <div>
              <div>   hello,world , my name is { name }</div>
              改变name <input onChange={ (e)=> setValue(e.target.value)  }  />
              <button onClick={ ()=>  changeName(value) }  >确定</button>
          </div>
      }
      
      export default classHOC(Index)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27

      我们看这个例子,代理组件中changeName={this.changeName.bind(this)} ,绑定changeName方法。用来更新name属性(代理组件中,说实话让我想起来了闭包)。

      题外话:上面的例子中changeName绑定的是一个函数,然后利用bind改变其this指向(返回值是一个函数),在Index组件使用的时候 , 才可以正确更新到代理组建的state。如果不绑定就会找不到该方法。

    2. 控制渲染
      代理组件通过处理可以控制子组件是否显示

      可以通过变量控制,也可以通过其它方式。达到控制渲染的目的就可以了

      我们来看一个优化的例子💨

          function HOC (Component){
              return function renderWrapComponent(props){
                  const { num } = props
                  const RenderElement = useMemo(() =>  <Component {...props}  /> ,[ num ])
                  return RenderElement
              }
          }
          class Index extends React.Component{
          render(){
              console.log(`当前组件是否渲染`,this.props)
              return <div>hello,world, my name is alien </div>
          }
          }
          const IndexHoc = HOC(Index)
      
          export default ()=> {
              const [ num ,setNumber ] = useState(0)
              const [ num1 ,setNumber1 ] = useState(0)
              const [ num2 ,setNumber2 ] = useState(0)
              return <div>
                  <IndexHoc  num={ num } num1={num1} num2={ num2 }  />
                  <button onClick={() => setNumber(num + 1) } >num++</button>
                  <button onClick={() => setNumber1(num1 + 1) } >num1++</button>
                  <button onClick={() => setNumber2(num2 + 1) } >num2++</button>
              </div>
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26

      上面的例子应该很好理解,代理组件通过useMemo钩子来依据props传入的num,来决定是否更新子组件

    3. 劫持生命周期

      function HOC (Component){
        const proDidMount = Component.prototype.componentDidMount 
        Component.prototype.componentDidMount = function(){
           console.log('劫持生命周期:componentDidMount')
           proDidMount.call(this)
        }
        return class wrapComponent extends React.Component{
            render(){
              return <Component {...this.props}  />
            }
        }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

      也是很好理解,代理组件保存子组建的生命周期函数,然后重新设置对应的生命周期函数

    4. 事件处理

      我们来看分析下面这个例子💨

      function ClickHoc (Component){
        return  function Wrap(props){
          const dom = useRef(null)
          useEffect(()=>{
           const handerClick = () => console.log('发生点击事件') 
           dom.current.addEventListener('click',handerClick)
           return () => dom.current.removeEventListener('click',handerClick)
          },[])
          return  <div ref={dom} ><Component  {...props} /></div>
        }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      其实就是代理组件上面加了一个click监听事件

    5. 获取自定义组件ref

      我们知道在自定义组件上面ref是无用的,我们可以使用代理组件包裹业务组件即可,ref={dom}在代理组件上,即可获取

       return  <div ref={dom} ><Component  {...props} /></div>
      
      • 1

    高阶组件实践

    可以参卡`推荐文章`中的这一章节,写的很详细
    
    • 1

    推荐文章

    「react进阶」一文吃透React高阶组件(HOC)

  • 相关阅读:
    记录一次win10系统27寸屏幕字体模糊的优化
    Vue应用方法、实例属性、实例方法$refs、vm.$nextTick等
    Maven - 5 分钟快速通关
    2023 “华为杯” 中国研究生数学建模竞赛(E题)深度剖析|数学建模完整代码+建模过程全解全析
    北斗导航 | RTCM 3.3学习(10403.3)
    人工智能在电力系统中的应用前景怎么样
    Spring注解开发
    PHP 发送邮件
    Java面试题-Redis-第三天(缓存更新策略-由旁路缓存策略衍生出的一系列问题)
    Vue3对话框样式修改不了
  • 原文地址:https://blog.csdn.net/qq_45859670/article/details/136723238