HOC的理解

710 阅读3分钟

HOC是什么?

HOC(Higher-Order Component)又名高阶组件,它是一个函数组件,他的参数为组件,返回值也是一个组件。

高阶组件的作用在于强化组件,复用逻辑,提升渲染性能等作用。

强化组件的几种方式

  • mixin模式:可能因为mixin有先后顺序甚至代码冲突覆盖问题,如果新增功能组件本身有了,将会被mixin功能给覆盖
  • extends继承模式:在class组件盛行之后,通过继承的方式进一步强化组件。
  • HOC模式:HOC更多的像是在一层一层的包装一个组件,给它添加新的功能
  • 自定义Hook:hook本身就是一个函数,自定义一个通用的hook,并将其挂载到函数组件上使用,也是在添加功能。

高阶组件的作用

  1. 复用逻辑:批量对原有组件进行加工,包装处理,根据业务需求定制化专属HOC,解决复用逻辑。
  2. 强化props:劫持上一层传过来的props,混入新的props,从而增强组件功能。(withRouter函数)
  3. 赋能组件:给固定类型的业务组件拓展功能,比如添加额外的生命周期和事件。(react-keepalive-router)
  4. 控制渲染:通过HOC可以对原组件进行条件渲染,节流渲染,懒加载等功能

HOC的使用方式

  • 装饰器模式:对于类组件可以使用,越靠近组件就是越内层的HOC
  • 函数包裹模式:

模型

// 无参数直接return组件
function withRouter(){    
    return class wrapComponent extends React.Component{        
        /* 编写逻辑 */    
    }
}

// 有参数需要多一层代理
function connect (mapStateToProps){    /* 接受第一个参数 */    
    return function connectAdvance(wrapCompoent){        
    /* 接受组件 */        
        return class WrapComponent extends React.Component{  }    
    }
}

高阶组件的两种方式

  • 正向代理(对目标组件进行一层包装,达到强化)

    使用场景:属性增强,条件渲染,权限隔离,懒加载,延时加载,一般情况下,不需要知道业务组件做了什么

    优点:完全隔离业务组件的渲染,可以控制业务组件的渲染;可以多个HOC嵌套使用

//正向代理:父组件对子组件进行强化操作
function HOC(WrapComponent){    
    return class Advance extends React.Component{       
        state={           
            name:'alien'       
        }       
        render(){           
            return <WrapComponent {...this.props} {...this.state} />
       }    
    }
}
  • 反向继承(继承目标组件,并在此基础上添加功能,所以,目标组件无需进行实例化)

    使用场景:

    优点:方便获取组件内部状态,比如state,props,生命周期等;可以继承静态属性

    缺点:如果多个反向继承HOC嵌套,会导致相同状态被改写

    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. 运用首次渲染的副作用,让组件自动加入渲染队列
  2. 利用组件实例作用域相互独立的知识,每个组件的回调函数都只改变自身数据

以下是实现的伪代码

const renderQueue = []
let isFirstrender = false
const tryRender = ()=>{  
    const render = renderQueue.shift()  
    if(!render) return  
    setTimeout(()=>{    
        render() /* 执行下一段渲染 */  
    },300)
} 
/* HOC */
function renderHOC(WrapComponent){    
    return function Index(props){      
        const [ isRender , setRender ] = useState(false)      
        useEffect(()=>{        
            renderQueue.push(()=>{  /* 放入待渲染队列中 */          
                setRender(true)        
            })        
            if(!isFirstrender) {          
                tryRender() /**/          
                isFirstrender = true        
            }      
        },[])      
        return isRender ?  : <WrapComponent tryRender={tryRender} {...props}/>: <div class="loading"></div>
}

/* 业务组件 */
class Index extends React.Component{  
    componentDidMount(){    
        const { name , tryRender} = this.props    
        /* 上一部分渲染完毕,进行下一部分渲染 */    
        tryRender()    
        console.log( name+'渲染')  
    }  
    render(){    
        return <div>组件{name}</div>
  }}
  /* 高阶组件包裹 */
  const Item = renderHOC(Index)
  export default () => {  
      return <React.Fragment>
          <Item name="组件一" />
          <Item name="组件二" />
          <Item name="组件三" />
      </React.Frgment>
}

在react中常用的HOC是?

  • withRoute——强化props
  • connect——结合context,监听store中的state变化,控制目标组件的渲染
  • keepalive——赋能组件