当前期刊数: 31
本期精读的文章是:我不再使用高阶组件。
懒得看文章?没关系,稍后会附上文章内容概述,同时,更希望能通过阅读这一期的精读,穿插着深入阅读原文。
1 引言
React 与 Vue 相比,组件为一等公民是最大特色之一。
由于组件可以作为一个 props 向下传递,因此 React 具备了高度抽象化的能力,Vue 虽然更易上手,但因 template 特点,没有所谓 props 传递组件这种概念,但这样导致在抽象能力上落后于 React。可能这是 JSX 与 template 之间的差异吧,也是变量与字符串之间的差异,变量同名但含义不同,所以可抽象,而模版靠规则和名称确定含义。
当然 Vue 也有 babel-plugin-transform-vue-jsx 这里不做展开。
强大的组件能力,导致了实践的多样性,高阶组件就是其一。高阶组件的特点是,JSX 描述的子元素,会注入到父级组件的 this.props.children
中,因此可以无入侵增强组件能力,常用比如权限、跳转、埋点、异常、描述、注入等等。
高阶组件也带来了使用中的困扰,作者这篇文章阐述了高阶组件存在的问题,值得我们了解。
2 内容概要
高阶组件由于可嵌套,如果有一环高阶组件没有将内部 wrappedComponent
暴露出来,会导致后续叠加的高阶组件都无法获取、注入到原始组件。
另外就算所有高阶组件都遵循了规范,组件也难以察觉被注入的数据是由哪些高阶组件提供的,而且高阶组件之间互相隔离,导致可能存在覆盖 props 的危险情况,这些问题高阶组件都束手无策。这体现出约定比约束更加效率,但约定的可维护性低于约束。
因此更好的解决思路可能是叫做 render props
render callback
function as child
这些名字的方法,组件定义如下:
1 |
|
直接将函数作为子元素,可以认为是一个匿名组件:
1 |
|
这种用法在 React Motion React Router 里都有采用。
3 精读
本质是将组件作为参数
我们看另一种写法:
1 |
|
render props
本质上与上面这种很常规的写法没什么不同,差异在于利用了 props.children
,将参数写在 JSX 的子元素中。相比高阶组件用法,这样嵌套下来,看得清楚数据流动,解决了高阶组件反复嵌套导致的各类问题:
1 |
|
与高阶组件对比
与 HOC 相比,render props 开放性提升明显,原本 HOC 所做的功能抽象可通过 render Props 获取,而 render 也可以访问到父级的一切:
Render Props 存在的问题
this.props.children
不该作为函数调用。- 渲染粒度变大,表格等需要性能优化的场景不适合。
- renderProps 渲染的并不是 React 组件,无法为其单独使用
redux
,mobx
dob
等依赖收集粒度也放不下去。
renderProps
为了解耦,让控制权从上到下传递,而底层实现不需要了解上层实现,这是解决 JSX 修改组件模版问题的方法之一,作为优化点之一,可以考虑让传入的 props 自身作为一个组件:
1 |
|
简约即美
与其绕那么大一圈,还不如回归到最普通的 props 传参,这说明 renderProps
作为其中一种特例,可能观赏价值大于其实用价值。其控制放权的思想也是为了解决组件 dom 结构定制化的问题。
但是这也涉及到限度的问题,以下就是两种极端:
1 |
|
1 |
|
可以看出,写出这两种代码的目的,都为了从外部控制组件结构,以至于最大限度提高组件的复用能力。其实很难在不了解组件自身含义时,妄下一个通用的结论,说 “你只要这么写,就能保证任何组件都非常通用”。
比如 Card
组件可以将 title
extra
设定为 ReactNode,加上 children
,其实用性已经足够了:
1 |
|
再比如 Modal
也只需要对 Header
Footer
children
支持 ReactNode 就可以保证足够的通用性。
在业务场景,由于代码修改频率较高,复用性重要程度就没那么高。
4. 总结
作者也提到了,高阶组件在某些场景很有用,所以不会完全拒绝使用。
在不为组件做注入的场景下是高阶组件的好场景,利用其生命周期实现权限、埋点,在层级少的时候用作依赖注入也非常方便。
其实程序员在思考这些最佳实践时,与艺术家的思考方式很类似,况且这些最佳实践在不同场景、不同团队,不同项目下都有所侧重,所以不用逮着所谓最完美的实践把代码全部重构,以后也全部用一种风格写代码。就像陶瓷艺术家也不会说:我再也不做彩瓷了,因为白瓷这种颜色非常简约,在我心中是完美的,因此我宁愿一辈子只做白瓷。
这一期也想表达一个积极含义,精读周刊是不会 give up 的!
如果你想参与讨论,请点击这里,每周都有新的主题,每周五发布。