HOC vs Render Props vs Hooks
相关问题
- 什么是 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)的规则,会造成项目臃肿和难以维护的问题。较早的方案是使用 HOC / Render Props 进行重构,然而这两种方案都会改变组件层级,容易形成“嵌套地狱”,使得代码的可读性下降。而 React Hooks 则很好地解决了这个问题。
方案优劣
为辅助理解,可参考以下图片。图中所示为下拉列表功能的三种不同实现,相比于使用一个 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 所需的依赖数组的处理会造成较大的心智负担。