HOC是什么?
HOC(Higher-Order Component)又名高阶组件,它是一个函数组件,他的参数为组件,返回值也是一个组件。
高阶组件的作用在于强化组件,复用逻辑,提升渲染性能等作用。
强化组件的几种方式
- mixin模式:可能因为mixin有先后顺序甚至代码冲突覆盖问题,如果新增功能组件本身有了,将会被mixin功能给覆盖
- extends继承模式:在class组件盛行之后,通过继承的方式进一步强化组件。
- HOC模式:HOC更多的像是在一层一层的包装一个组件,给它添加新的功能
- 自定义Hook:hook本身就是一个函数,自定义一个通用的hook,并将其挂载到函数组件上使用,也是在添加功能。
高阶组件的作用
- 复用逻辑:批量对原有组件进行加工,包装处理,根据业务需求定制化专属HOC,解决复用逻辑。
- 强化props:劫持上一层传过来的props,混入新的props,从而增强组件功能。(withRouter函数)
- 赋能组件:给固定类型的业务组件拓展功能,比如添加额外的生命周期和事件。(react-keepalive-router)
- 控制渲染:通过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的副作用将控制自己是否渲染的函数放入渲染队列中,当渲染队列逐个执行回调函数时,将改变组件内部的布尔值,从而渲染真正的业务组件。
- 运用首次渲染的副作用,让组件自动加入渲染队列
- 利用组件实例作用域相互独立的知识,每个组件的回调函数都只改变自身数据
以下是实现的伪代码
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——赋能组件