组件复用:HOC、Render Props、自定义Hook 对比

在 React 中,组件逻辑复用经历了三个主要阶段:

  1. HOC(Higher Order Component,高阶组件)
  2. Render Props(渲染属性)
  3. Custom Hook(自定义 Hook)

目前 React 官方推荐使用 Custom Hook 进行逻辑复用,但面试中经常会让你比较三者的区别。


一、HOC(Higher Order Component)

定义

高阶组件本质上是一个函数:

javascript 复制代码
const withLoading = (WrappedComponent) => {
  return (props) => {
    const [loading] = useState(false);

    if (loading) {
      return <div>Loading...</div>;
    }

    return <WrappedComponent {...props} />;
  };
};

使用:

javascript 复制代码
const UserList = () => {
  return <div>用户列表</div>;
};

export default withLoading(UserList);

原理

scss 复制代码
Component
    ↓
withXXX(Component)
    ↓
NewComponent

本质:

css 复制代码
A => B

输入一个组件,返回一个增强后的组件。


常见场景

权限校验

javascript 复制代码
const withAuth = (Component) => {
  return (props) => {
    const token = localStorage.getItem('token');

    if (!token) {
      return <div>请登录</div>;
    }

    return <Component {...props} />;
  };
};

日志埋点

javascript 复制代码
const withLog = (Component) => {
  return (props) => {
    console.log('页面访问');

    return <Component {...props} />;
  };
};

优点

逻辑复用

scss 复制代码
withAuth(User)
withAuth(Order)
withAuth(Product)

对原组件无侵入

arduino 复制代码
export default withAuth(User);

User 不需要修改代码。


缺点

1. HOC 地狱

arduino 复制代码
export default withAuth(
  withLoading(
    withLog(
      withTheme(User)
    )
  )
);

嵌套过深。


2. Props 命名冲突

ini 复制代码
<Component data={data} />

如果组件本身也有 data 属性:

ini 复制代码
<User data="xxx" />

容易覆盖。


3. 调试困难

React DevTools:

scss 复制代码
withAuth(
  withTheme(
    User
  )
)

组件树很难看。


二、Render Props

定义

通过函数作为 props 传递逻辑。

ini 复制代码
<DataProvider
  render={(data) => (
    <UserList data={data} />
  )}
/>

示例

数据提供组件

scala 复制代码
class Mouse extends React.Component {
  state = {
    x: 0,
    y: 0
  };

  componentDidMount() {
    window.addEventListener('mousemove', this.handleMove);
  }

  handleMove = (e) => {
    this.setState({
      x: e.clientX,
      y: e.clientY
    });
  };

  render() {
    return this.props.render(this.state);
  }
}

使用:

javascript 复制代码
<Mouse
  render={({ x, y }) => (
    <h1>
      {x}, {y}
    </h1>
  )}
/>

children 也是 Render Props

javascript 复制代码
<Mouse>
  {({ x, y }) => (
    <h1>{x},{y}</h1>
  )}
</Mouse>

组件:

kotlin 复制代码
return this.props.children(this.state);

优点

灵活

调用方完全控制 UI:

ini 复制代码
<DataProvider
  render={(data) => (
    <CustomTable data={data} />
  )}
/>

不会产生 HOC 嵌套

xml 复制代码
<DataProvider />

结构更清晰。


缺点

JSX 嵌套严重

javascript 复制代码
<DataProvider>
  {(data) => (
    <ThemeProvider>
      {(theme) => (
        <User />
      )}
    </ThemeProvider>
  )}
</DataProvider>

俗称:

复制代码
Callback Hell

性能问题

每次 render:

ini 复制代码
render={(data)=>{}}

都会创建新的函数。


三、自定义 Hook(Custom Hook)

React 16.8 之后最主流方案。


示例

封装鼠标位置

scss 复制代码
function useMouse() {
  const [position, setPosition] = useState({
    x: 0,
    y: 0
  });

  useEffect(() => {
    const move = (e) => {
      setPosition({
        x: e.clientX,
        y: e.clientY
      });
    };

    window.addEventListener('mousemove', move);

    return () => {
      window.removeEventListener('mousemove', move);
    };
  }, []);

  return position;
}

使用

javascript 复制代码
function App() {
  const { x, y } = useMouse();

  return (
    <h1>
      {x} - {y}
    </h1>
  );
}

多组件共享逻辑

scss 复制代码
function User() {
  const { data } = useUser();
}

function Order() {
  const { data } = useUser();
}

优点

1. 代码最简洁

ini 复制代码
const data = useUser();

没有嵌套。


2. 逻辑聚合

go 复制代码
const {
  data,
  loading,
  error
} = useFetch();

逻辑放一起。


3. TypeScript 友好

arduino 复制代码
function useUser(): UserInfo {}

类型推导自然。


4. 不增加组件层级

React 树:

sql 复制代码
App
 └ User

不会出现:

scss 复制代码
withAuth(User)

或者:

markdown 复制代码
Provider
 └ render
    └ User

缺点

只能用于函数组件

scala 复制代码
class User extends React.Component {}

不能直接使用:

scss 复制代码
useUser()

必须遵守 Hook 规则

错误:

scss 复制代码
if (visible) {
  useUser();
}

正确:

ini 复制代码
const user = useUser();

if (visible) {}

四、三者对比

对比项 HOC Render Props Custom Hook
出现时间 React 早期 React 16 前后 React 16.8+
本质 组件包装组件 函数作为 props Hook 抽离逻辑
增加组件层级
JSX 嵌套
逻辑复用 最好
TypeScript 支持 一般 一般 很好
调试体验 一般
性能 一般 一般
推荐程度 ⭐⭐ ⭐⭐ ⭐⭐⭐⭐⭐

五、面试回答(标准版)

如果面试官问:

React 中 HOC、Render Props、自定义 Hook 有什么区别?

可以回答:

三者本质上都是为了解决组件间逻辑复用问题。

  • HOC 是通过包装组件返回增强组件来复用逻辑,适用于权限控制、埋点统计等场景,但容易出现组件嵌套和 props 冲突问题。
  • Render Props 是通过函数作为 props 传递共享逻辑,灵活性较高,但容易造成 JSX 嵌套过深。
  • Custom Hook 是 React Hooks 推出后的推荐方案,通过抽离状态逻辑实现复用,不增加组件层级,代码更简洁、类型支持更好,也是当前 React 项目中最常用的方案。

在现代 React 开发中,优先使用 Custom Hook;维护老项目时仍然会遇到 HOC 和 Render Props。

相关推荐
Gauss松鼠会1 小时前
【GaussDB】GaussDB SMP特性调优详解
java·服务器·前端·数据库·sql·算法·gaussdb
葬送的代码人生1 小时前
JavaScript 数组完全指南:从入门到实战
前端·javascript·算法
用户938515635072 小时前
深入理解 JavaScript 同步与异步:从单线程到事件循环与 Promise
前端·javascript
搬砖的码农2 小时前
造一个 Agent 运行时 #01:我决定开干,顺便把坑都写下来
前端·agent·ai编程
yingyima2 小时前
深入解析:定时任务失败重试机制的底层原理与实践
前端
哈撒Ki2 小时前
快速入门vue3与常见面试题
前端·vue.js·面试
踩着两条虫2 小时前
VTJ.PRO v2.4.2 私有化部署与升级实操指南
前端·人工智能·低代码·架构·数据挖掘
木斯佳2 小时前
前端八股文面经大全:美团前端暑期实习一面(2026-06-08)·面经深度解析
前端
Uso_Magic2 小时前
VOL_实现APP多文件上传_前端多文件显示!
前端