HOC 与 Render Props

React 中两种代码复用模式的区别与使用场景

问题

React 高阶组件 (HOC) 与 Render Props 的区别与应用。

解答

高阶组件 (HOC)

HOC 是一个函数,接收组件作为参数,返回增强后的新组件。

// 创建一个添加鼠标位置追踪功能的 HOC
function withMouse(WrappedComponent) {
  return class extends React.Component {
    state = { x: 0, y: 0 };

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

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

    componentWillUnmount() {
      window.removeEventListener('mousemove', this.handleMouseMove);
    }

    render() {
      // 将鼠标位置作为 props 传递给被包裹组件
      return <WrappedComponent {...this.props} mouse={this.state} />;
    }
  };
}

// 使用 HOC
function DisplayPosition({ mouse }) {
  return (
    <p>
      鼠标位置: ({mouse.x}, {mouse.y})
    </p>
  );
}

const EnhancedDisplay = withMouse(DisplayPosition);

Render Props

Render Props 是通过 props 传递一个渲染函数,让组件知道如何渲染内容。

// 创建一个提供鼠标位置的组件
class Mouse extends React.Component {
  state = { x: 0, y: 0 };

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

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

  componentWillUnmount() {
    window.removeEventListener('mousemove', this.handleMouseMove);
  }

  render() {
    // 调用 render prop 函数,传入当前状态
    return this.props.render(this.state);
  }
}

// 使用 Render Props
function App() {
  return (
    <Mouse
      render={({ x, y }) => (
        <p>
          鼠标位置: ({x}, {y})
        </p>
      )}
    />
  );
}

使用 children 作为函数

Render Props 的变体,更简洁:

class Mouse extends React.Component {
  state = { x: 0, y: 0 };
  // ... 同上

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

// 使用
function App() {
  return (
    <Mouse>
      {({ x, y }) => (
        <p>
          鼠标位置: ({x}, {y})
        </p>
      )}
    </Mouse>
  );
}

对比

特性HOCRender Props
使用方式函数包裹组件组件内传递渲染函数
Props 来源隐式注入显式传递
组合多个功能嵌套调用嵌套组件
静态组合✅ 编译时确定❌ 运行时确定
调试体验组件层级深相对清晰

现代替代方案:Hooks

// 自定义 Hook 实现相同功能
function useMouse() {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  useEffect(() => {
    const handleMove = (e) => {
      setPosition({ x: e.clientX, y: e.clientY });
    };
    window.addEventListener('mousemove', handleMove);
    return () => window.removeEventListener('mousemove', handleMove);
  }, []);

  return position;
}

// 使用
function App() {
  const { x, y } = useMouse();
  return (
    <p>
      鼠标位置: ({x}, {y})
    </p>
  );
}

关键点

  • HOC 是函数,接收组件返回新组件;Render Props 是通过 props 传递渲染函数
  • HOC 的 props 是隐式注入的,可能产生命名冲突;Render Props 显式传递,更清晰
  • HOC 适合静态增强,Render Props 适合动态渲染逻辑
  • 多个 HOC 嵌套会形成”包装地狱”,调试困难
  • 现代 React 推荐使用 Hooks 替代这两种模式,更简洁且无嵌套问题