React 高阶组件HOC(High Order Component)

HOC (High Order Component)

  • 高阶组件:
    • 定义:一个函数组件,接收一个组件作为参数,返回一个新的增强的组件,可以为组件添加预定义的props,统一样式、逻辑
  • 注意:编写高阶组件时,组件名应为小驼峰,否则eslint等会认为这是一个正常的JSX组件,在回调中编写Hook会警告;

实操

接下来编写一个Button和Modal,

  • Button具有权限校验的功能,并可以打开Modal,
  • Modal中有统一样式的Title 以及 加载状态(提供加载前后的显式状态);

以这样一个Demo来演示HOC的使用场景,这里我们会借助Antd的Button和Modal对其进行二次封装

源码:Github Link

withAuth

js 复制代码
function withAuth(InnerComponent) {

  return function(props){
    const [hasAuth,setHasAuth] = useState(false);

    useEffect(()=>{
        async function checkAuth(){
            setTimeout(()=>{
                //模拟获取当前用户有权限
                setHasAuth(true);
            },1000);
        }
        checkAuth();
    })

    if(!hasAuth) return void 0;

    return <InnerComponent {...props}/>
  }
}

然后是进一步封装AuthButton,这里要注意的是AuthButton的props中可以接收我们在withAuth中返回的InnerComponent的props,即 return <InnerComponent {...props}/>;

js 复制代码
function AuthButton({...props}){
    return <Button {...props}>
        {props.children}
    </Button>
}

export default withAuth(AuthButton);

在这个例子中我们在withAuth高阶组件中维护了一个状态,该状态来决定是否渲染接收的组件InnerComponent。

withStyleAndLoading

然后就是Modal了,首先编写带有样式和Loading状态的HOC

js 复制代码
function withStyleAndLoading(InnerComponent,delay,titleText) {
  return (props) =>{
    const [loading,setLoading] = useState(true);

    useEffect(()=>{
      setTimeout(()=>{
        setLoading(false);
      },delay);
    },[])

    const withStyleTitle = <div style={{color:'red'}}>{titleText}</div>
    return <InnerComponent {...props} loading={loading} title={withStyleTitle}>
      {loading ? 'loading...': void 0}
    </InnerComponent>
  }
}

可以看到我们为InnerComponent增强了props,传递了loading状态以及具有统一样式的Title。 这里的delay是为了模拟请求,实际开发中可以传入请求的url,然后再根据请求结果改变loading状态;

然后我们对Modal进行封装:

js 复制代码
function StyleAndLoadingModal({loading,children:loadingDom,...props}){
  useEffect(()=>{
    if(loading){
      console.log('loading...');
    }else{
      console.log('loaded');
    }
  },[loading])
  return (
    <Modal {...props}>
      {loadingDom}
    </Modal>
  )
}

export default withStyleAndLoading(StyleAndLoadingModal,2000,"This is Title");

至此,我们就可以进一步使用了:

js 复制代码
function App() {

  const [open,setOpen] = useState(false)
  const openModal = ()=>{
    setOpen(true);
  }
  
  return (
    <>
      <AuthButton onClick={openModal}>open</AuthButton>
      <StyleAndLoadingModal open={open}></StyleAndLoadingModal>
    </>
  );
}

我们可以看到,AuthButton会在校验成功后渲染,渲染后,由于请求Modal中请求还没有完成,我们此时打开Modal还可以看到Loading,并且Title的样式也成功渲染了。

总结

强烈建议大家都手敲一遍,然后可能还有困惑,接下来我们再总结一波:

高阶组件HOC实际上包括以下几个功能:

  1. 他类似于一个包装函数,接收一个组件,和实现功能的一些参数,我们可以利用这些参数为InnerComponent提供一些功能;(url,titleText)
  2. 他可以在渲染InnerComponent前使用Hook来实现一些共同逻辑;(权限校验,loading展示)
  3. 可以为返回的InnerComponent传递一些预定义的props来增强组件,这些props可以在外部被我们使用(loading状态)

可以将高阶组件的编写分为以下几个阶段:

  • 首先是入参阶段,这些入参中包括InnerComponent和一些参数,为后面几个阶段提供支持;
  • 然后是组件返回前阶段,这个阶段可以自定义一些状态,变量以及使用Hook来完成一些功能或产生新的变量;
  • 接下来是返回阶段,这个阶段可以使用前面的所有所有状态,变量来指定要渲染的InnerComponent,将上面两个阶段中的变量转换为props进行传递;
  • 然后是InnerComponent的定义阶段,在编写具体的InnerComponent时,要对接的是上一个阶段中预定义的props,这些props可以供具体的InnerComponent使用;
  • 最后是暴露阶段,我们要对接的是第一个阶段中的入参,也可以说是HOC的实用阶段;
相关推荐
伍哥的传说43 分钟前
Mitt 事件发射器完全指南:200字节的轻量级解决方案
vue.js·react.js·vue3·mitt·组件通信·事件管理·事件发射器
随笔记9 小时前
react-router里的两种路由方式有什么不同
前端·react.js
晴空雨12 小时前
React 合成事件原理:从事件委托到 React 17 的重大改进
前端·react.js
@大迁世界12 小时前
useCallback 的陷阱:当 React Hooks 反而拖了后腿
前端·javascript·react.js·前端框架·ecmascript
Fantastic_sj12 小时前
React 19 核心特性
前端·react.js·前端框架
小高00712 小时前
📌React 路由超详解(2025 版):从 0 到 1 再到 100,一篇彻底吃透
前端·javascript·react.js
wwy_frontend13 小时前
React性能优化实战:从卡顿到丝滑的8个技巧
前端·react.js
ikonan15 小时前
译:不要过度优化你的优化
前端·javascript·react.js
mit6.82417 小时前
[AI React Web] 包与依赖管理 | `axios`库 | `framer-motion`库
前端·人工智能·react.js
晓得迷路了18 小时前
栗子前端技术周刊第 94 期 - React Native 0.81、jQuery 4.0.0 RC1、Bun v1.2.20...
前端·javascript·react.js