React高阶组件详解

高阶组件是什么?

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

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

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

认识高阶组件

  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 }  />
          }
        }
      }
    

    我们来看一下上面这个例子,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) 
    

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

编写高阶组件

很多文章对其有很多分类,我这里就按照我的理解去分类
  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)
    

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

    题外话:上面的例子中changeName绑定的是一个函数,然后利用bind改变其this指向(返回值是一个函数),在Index组件使用的时候<button onClick={ ()=> changeName(value) } >确定</button> , 才可以正确更新到代理组建的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>
        }
    

    上面的例子应该很好理解,代理组件通过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}  />
          }
      }
    }
    

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

  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>
      }
    }
    

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

  5. 获取自定义组件ref

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

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

高阶组件实践

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

推荐文章

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

相关推荐

  1. React组件详解

    2024-03-18 09:42:05       21 阅读
  2. 使用React组件

    2024-03-18 09:42:05       9 阅读
  3. react组件——withRouter

    2024-03-18 09:42:05       10 阅读
  4. react的withRouter组件

    2024-03-18 09:42:05       34 阅读
  5. React组件|ref转发

    2024-03-18 09:42:05       39 阅读
  6. react组件怎么用?

    2024-03-18 09:42:05       19 阅读
  7. React中的组件

    2024-03-18 09:42:05       15 阅读
  8. React基础三】组件传值、组件、Hook

    2024-03-18 09:42:05       38 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-18 09:42:05       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-18 09:42:05       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-18 09:42:05       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-18 09:42:05       20 阅读

热门阅读

  1. Flutter 当涉及Listview的复杂滑动布局良好布局方式

    2024-03-18 09:42:05       18 阅读
  2. Python实现连连看

    2024-03-18 09:42:05       15 阅读
  3. 如何优化查询ORM

    2024-03-18 09:42:05       19 阅读
  4. IDEA SpringBoot + Gradle无法运行测试问题

    2024-03-18 09:42:05       19 阅读
  5. Spring Data访问Elasticsearch----Elasticsearch对象映射

    2024-03-18 09:42:05       22 阅读
  6. Spring Boot(七十):利用Jasypt对数据库连接进行加密

    2024-03-18 09:42:05       18 阅读
  7. 如何在MATLAB中处理图像和视频?

    2024-03-18 09:42:05       17 阅读
  8. tcpudp面试题

    2024-03-18 09:42:05       18 阅读
  9. vue的一些个人理解

    2024-03-18 09:42:05       22 阅读
  10. 怎样合理规划游戏的玩法、关卡结构及剧情线?

    2024-03-18 09:42:05       22 阅读