HOC vs Render Props vs Hooks

完整高频题库仓库地址:https://github.com/hzfe/awesome-interview

完整高频题库阅读地址:https://febook.hzfe.org/

相关问题

  • 什么是 HOC / Render Props / Hooks
  • 为什么需要 HOC / Render Props / Hooks
  • 如何提高代码复用性
  • Hooks 的实现原理
  • Hooks 相比其他方案有什么优势

回答关键点

复用性

HOC / Render Props / Hooks 三种写法都可以提高代码的复用性,但实现方法不同:HOC 是对传入的组件进行增强后,返回新的组件给开发者;Render Props 是指将一个返回 React 组件的函数,作为 prop 传给另一个 React 组件的共享代码的技术;Hooks 是 React 提供的一组 API,使开发者可以在不编写 class 的情况下使用 state 和其他 React 特性。

知识点深入

1. HOC (Higher Order Component,即高阶组件)

HOC 是 React 中复用代码的编程模式。具体来说,高阶组件是一个纯函数,它接收一个组件并返回一个新的组件。常见例子:React Redux 的 connect,将 Redux Store 和 React 组件联系起来。

// react-redux connect 例子
const ConnectedMyComponent = connect(mapState)(MyComponent);
// 实现一个简单的 HOC 例子
function logProps(WrappedComponent{
  return class extends React.Component {
    componentDidUpdate(prevProps) {
      console.log("Current props: "this.props);
      console.log("Previous props: ", prevProps);
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
}

2. Render Props

Render Props 是 React 中复用代码的编程模式。主要解决组件逻辑相同而渲染规则不同的复用问题。常见例子:React Router 中,自定义 render 函数,按需使用 routeProps 来渲染业务组件。

ReactDOM.render(
  <Router>
    <Route
      path="/home"
      render={(routeProps) =>
 (
        <div>Customize HZFE's {routeProps.location.pathname}</div>
      )}
    />
  </Router>
,
  node
);

3. React Hooks

React Hooks 是 React 16.8 引入的一组 API。开发者可以在不使用 class 写法的情况下,借助 Hooks 在纯函数组件中使用状态和其他 React 功能。

function Example({
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>

  );
}

4. HOC vs Render Props vs Hooks

痛点

在实际业务快速迭代过程中,组件常出现大量重复性工作,少量个性化定制的需求,如果不遵循 DRY(Don't Repeat Yourself)的规则,会造成项目臃肿和难以维护的问题。但在许多情况下,无法对含有状态逻辑的组件进一步拆分。因此在没有 React Hooks 前,存在使用 HOC / Render Props 进行重构的方案。

方案优劣

为辅助理解,可参考以下图片。图中所示为下拉列表功能的三种不同实现,相比于使用一个 Class 来书写下拉列表的所有功能,这三种方案都对组件进行了功能拆解,提高了代码的复用性。 (代码来源

  • 复用性

    HOC、Render Props、Hooks 都有提高代码复用性的能力,但根据其设计模式上的差别,适用范围也会有所差异:HOC 基于单一功能原则,对传入组件进行增强;Render Props 复用数据源,按需渲染 UI;Hooks 对于不同场景的复用都有较好的普适性。

  • 可读性 / 易用性

    HOC 可读性差,易用性差。

    HOC 写法看似简洁,但开发者无法通过阅读 HOC 的调用辨别出方法的作用:看不到接收和返回的结构,增加调试和修复问题的成本;进行多个 HOC 组合使用时,不能确定使用顺序且有命名空间冲突风险,需要了解每个 HOC 的具体实现,难以维护。不建议过度使用 HOC,但比较适合不需要个性化开发定制时使用:常见于第三方库提供 HOC 类型的 API 给开发者进行功能增强。

    Render Props 可读性较好,易用性强。

    代码相对冗长,但能清晰看到组件接收的 props 以及传递的功能等,可以对 props 属性重命名,不会有命名冲突。但难以在 render 函数外使用数据源,且容易形成嵌套地狱。

    Hooks 可读性强,易用性较好。

    使用 Hooks 时,能清晰看到组件接收的 props 以及传递的功能等,可以对 props 属性重命名,不会有命名冲突,不存在嵌套地狱,且没有数据源获取及使用范围的限制。但 Hooks 编程应遵循函数式编程的实践,否则 Hooks 所需的依赖数组的处理会造成较大的心智负担。

参考资料

  1. Introducing Hooks
  2. Comparison: HOCs vs Render Props vs Hooks
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的示例: 假设有一个组件 `Counter`,它可以接受一个 `count` 属性用于控制计数器的初始值,同时提供一个 `increment` 方法用于增加计数器的值。我们来分别使用 `hook`、`hoc`、`render props` 来实现这个组件。 1. 使用 `hook` 使用 `useState` hook 来管理计数器的状态,并通过 `useCallback` hook 来创建 `increment` 方法,代码如下: ``` import React, { useState, useCallback } from 'react'; function Counter({ count }) { const [value, setValue] = useState(count); const increment = useCallback(() => { setValue(value => value + 1); }, []); return ( <div> <p>{value}</p> <button onClick={increment}>+1</button> </div> ); } ``` 2. 使用 `hoc` 使用高阶组件(Higher-Order Component,即 `hoc`)来将 `count` 属性和 `increment` 方法注入到 `Counter` 组件中,代码如下: ``` import React from 'react'; function withCounter(WrappedComponent) { return class extends React.Component { state = { value: this.props.count || 0 } increment = () => { this.setState(prevState => ({ value: prevState.value + 1 })); } render() { return ( <WrappedComponent value={this.state.value} increment={this.increment} {...this.props} /> ); } } } function Counter({ value, increment }) { return ( <div> <p>{value}</p> <button onClick={increment}>+1</button> </div> ); } export default withCounter(Counter); ``` 3. 使用 `render props` 通过将一个函数作为 `Counter` 组件的子组件,并将 `count` 属性和 `increment` 方法作为该函数的参数传递,来实现 `render props`。代码如下: ``` import React, { useState, useCallback } from 'react'; function Counter({ children, count }) { const [value, setValue] = useState(count); const increment = useCallback(() => { setValue(value => value + 1); }, []); return children(value, increment); } function App() { return ( <Counter count={0}> {(value, increment) => ( <div> <p>{value}</p> <button onClick={increment}>+1</button> </div> )} </Counter> ); } export default App; ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值