美文网首页
React 学习笔记二 - HOC 高阶组件理解

React 学习笔记二 - HOC 高阶组件理解

作者: 人话博客 | 来源:发表于2022-01-20 20:48 被阅读0次

    官方定义

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

    HOC 是单词 Heigher Order Component 缩写

    具体而言,<span style="color:red">高阶组件是参数为组件,返回值为新组件的函数。

    const EnhancedComponent = higherOrderComponent(WrappedComponent);
    

    从官方定义中,我们可以抽取以下重点:

    • 高阶组件就是一个函数.(没有说是构造函数,在React中,构造函数,你继承自 React.Component,它就是一个组件了)
    • 此函数接受一个组件作为参数.(就是接受一个继承自React.Component的构造函数作为参数)
    • 此函数返回一个组件.(必须返回一个继承自React.Component的构造函数)
    • <span style="color:red"> 逻辑复用.或者说组件的功能扩展.

    高阶组价,接受一个构造函数,返回一个构造函数. 所以,高阶组件就是一个概念. 它本质上也是高阶函数.

    react-redux 里面的 connect 函数,就是一个高阶组件.

    高级组件就是一个函数,接受一个一个组件(函数),返回一个新组件(函数)

    理解高阶组件.

    既然高阶组件,本质上是一个函数.那么我就给它一个组件作为入参,在返回一个组件即可.

    import React, { useState } from 'react'
    import './App.css';
    /**
     * 
     * 官方定义高阶组件(HOC)是 React 中用于**复用组件逻辑**的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。
       HOC 是单词 Heigher Order Component 缩写
       具体而言,高阶组件是参数为组件,返回值为新组件的函数。
     * 
     * 
     */
    
    function HelloComponent(props) {
      return (
        <div>
          <h2>我是一个定义的函数式组件 <span style={{ fontSize: '20px', color: '#f40' }}>{props.title}</span> </h2>
        </div>
      )
    }
    
    // 高阶组件就是一个函数,接收一个组件,返回一个[新]的组件.
    const withComponent = (Component) => {
      return function WrapperComponent() {
        const [title, setTitle] = useState('这是由内部组件 WrapperComponent 传递过来的 title')
        const changeTitle = () => {
          setTitle("这是新的 title")
        }
        return (
          <React.Fragment>
            <Component title={title} />
            <button onClick={changeTitle}>修改 title</button>
          </React.Fragment>
        )
      }
    }
    
    // 传入一个HelloComponent,作为入参
    // 返回一个HocComponent作为新的组件
    const HocComponent = withComponent(HelloComponent)
    
    function App() {
      return (
        <div className="App">
          <h2>Hello HOC - Highter Order Component</h2>
          <HocComponent />
        </div>
      );
    }
    export default App;
    
    

    可以正常工作.

    ![高阶组件简单使用images.jianshu.io/upload_images/2701794-d79d78664a4895aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


    将逻辑复用(功能扩展)逻辑设定在高阶组件中.

    上述例子,仅演示了高阶组件的用法和原理.

    这次,我们把逻辑复用和功能扩展加上去.

    这么一个例子

    • 有两组件. FooBar.
    • FooBar 组件的功能就是在屏幕视口宽度发生改变是,动态的把宽度数值显示出来.
    
    import React from 'react'
    import './App.css';
    /**
     * 
     * 官方定义高阶组件(HOC)是 React 中用于**复用组件逻辑**的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。
       HOC 是单词 Heigher Order Component 缩写
       具体而言,高阶组件是参数为组件,返回值为新组件的函数。
     * 
     * 
     */
    
    class Foo extends React.PureComponent {
      state = {
        sw: document.documentElement.clientWidth
      }
    
      componentDidMount () {
        window.addEventListener('resize', () => {
          this.setState(() => ({ sw: document.documentElement.clientWidth }))
        }, false)
      }
    
      componentWillUnmount () {
        window.removeEventListener('resize')
      }
    
      render () {
        return (
          <p className='FooContent'>当前的屏幕宽度为:{this.state.sw}</p>
        )
      }
    }
    
    class Bar extends React.PureComponent {
      state = {
        sw: document.documentElement.clientWidth
      }
    
      componentDidMount () {
        window.addEventListener('resize', () => {
          this.setState(() => ({ sw: document.documentElement.clientWidth }))
        }, false)
      }
    
      componentWillUnmount () {
        window.removeEventListener('resize')
      }
    
      render () {
        return (
          <button className='btn-content'>当前屏幕宽度为:{this.state.sw}</button>
        )
      }
    }
    
    function App () {
      return (
        <div className="App">
          <h2>Hello HOC - Highter Order Component</h2>
          <Foo />
          <Bar />
        </div>
      );
    }
    export default App;
    
    

    效果如图:

    [图片上传失败...(image-c468a2-1642682879317)]

    功能确实实现了.但是两组件除了渲染的位置,其他地方都是一致的.

    Vue中,我们可以使用 mixins 来解决组件间逻辑重复定义的问题.

    state , componentDidMount, componentWillUnmount 逻辑重复.

    React 中,我们就可以使用 Highter Order Component 高阶组件的方式,来抽取组件重复定义的逻辑部分.

    // 定义一个高阶组件函数,来抽取逻辑重复的位置,提高逻辑复用.
    const withResize = (Component) => {
        //xxxxx
    }
    

    具体代码如下:

    import React from 'react'
    import './App.css';
    /**
     * 
     * 官方定义高阶组件(HOC)是 React 中用于**复用组件逻辑**的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。
       HOC 是单词 Heigher Order Component 缩写
       具体而言,高阶组件是参数为组件,返回值为新组件的函数。
     * 
     * 
     */
    
    class Foo extends React.PureComponent {
      // state = {
      //   sw: document.documentElement.clientWidth
      // }
    
      // componentDidMount () {
      //   window.addEventListener('resize', () => {
      //     this.setState(() => ({ sw: document.documentElement.clientWidth }))
      //   }, false)
      // }
    
      // componentWillUnmount () {
      //   window.removeEventListener('resize')
      // }
    
      render () {
        return (
          <p className='FooContent'>当前的屏幕宽度为:{this.props.sw}</p>
        )
      }
    }
    
    class Bar extends React.PureComponent {
      // state = {
      //   sw: document.documentElement.clientWidth
      // }
    
      // componentDidMount () {
      //   window.addEventListener('resize', () => {
      //     this.setState(() => ({ sw: document.documentElement.clientWidth }))
      //   }, false)
      // }
    
      // componentWillUnmount () {
      //   window.removeEventListener('resize')
      // }
    
      render () {
        return (
          <button className='btn-content'>当前屏幕宽度为:{this.props.sw}</button>
        )
      }
    }
    
    // 定义一个高阶组件函数,来抽取逻辑重复的位置,提高逻辑复用.
    const withResize = (Component) => {
      return class WrappedComponent extends React.PureComponent {
        //#region 抽离组件通用的逻辑部分
        state = {
          sw: document.documentElement.clientWidth
        }
    
        componentDidMount () {
          window.addEventListener('resize', () => {
            this.setState(() => ({ sw: document.documentElement.clientWidth }))
          }, false)
        }
    
        componentWillUnmount () {
          window.removeEventListener('resize')
        }
        //#endregion
    
        render () {
          // 将需要的数据以 props 的方式传递给被包装的组件
          return <Component {...this.state} />
        }
      }
    }
    
    const FooWithResize = withResize(Foo)
    const BarWithResize = withResize(Bar)
    
    function App () {
      return (
        <div className="App">
          <h2>Hello HOC - Highter Order Component</h2>
          <h3>将通用逻辑抽离,以便复用!</h3>
          {/* <Foo />
          <Bar /> */}
          <FooWithResize />
          <BarWithResize />
        </div>
      );
    }
    export default App;
    
    
    
    • 将通用逻辑从 FooBar 组件中抽离.起到逻辑复用的作用.
    • FooBar 需要的数据以 props 的形式传入即可.
    高阶组件抽取通用逻辑以便复用.gif

    效果和上述是一致的.


    总结

    • 高阶组件就是一个函数仅此而已(javascript中不就是函数和对象吗?)
    • 高阶组件接受一个组件(可以是函数组件,也可以是class 组件)作为参数(普通函数,构造函数).
    • 返回一个新组件(可以是函数组件,也可是 class 组件),返回一个普通函数或者是构造函数.
    • 所以高阶组件也是一个高阶函数.
    • 将通用的逻辑抽离在高阶组件中,已达到复用的目的.

    码云地址

    相关文章

      网友评论

          本文标题:React 学习笔记二 - HOC 高阶组件理解

          本文链接:https://www.haomeiwen.com/subject/fchshrtx.html