上一篇文章,我们介绍了高阶组件(HOC),最后也提出了几个关于高阶组件的问题。这里我们接上另一种组件复用模式 render props
亦或是 funtion as child
。
render props
本质上,render props 就是在原有的组件上增加一个 prop 来实现不同的渲染情况,从而达到代码复用的目的(即将组件组件做为参数)。举例如下:
|
|
StareStateComponent 内部维护了一些可复用的功能,在实例化时,通过调用名为 render 的 prop 属性函数实现了不同组件的渲染。换个更直观的方案,我们可以直接利用 this.props.children
,通过执行 this.props.children 方法,来传递必要的参数,从而实现基于共享数据的不同渲染逻辑,达到复用的目的。这种用法在 React Motion
, React Router
里都有采用。
|
|
通过上面的代码,我们可以看到相比高阶组件,render props 的方案,我们更能直观的观察到数据的流动,从而解决了高阶组件的嵌套问题。与高阶组件相比,render props 的开放性得到提升,原本 HOC 所做的功能抽象可以通过 render props 获取,render 方式还可以直接访问父级的一切内容:
render props 存在的问题
render props 带来的优点:
- 不用担心props命名问题,在render函数中只取需要的state,数据流动更加直观
- 不会产生无用的组件加深层级
- render props模式的构建都是动态的,所有的改变都在render中触发,可以更好的利用组件内的生命周期。
- 能够直接访问父组件的内容,开发性更高
但 render props 也有一些不能忽视的问题:
- this.props.children 被重新定义为函数是否合适
- 渲染粒度变大,如果在属性中定义函数,浅比较下 prop 的值永远是新的,每次都将重新生成新的 prop,这将导致 React.PureComponent 不起作用
- renderProps 渲染的并不是 React 组件,无法为其单独使用 redux,mobx
- 容易产生嵌套地狱问题
当然,对于项目使用 HOC 还是 render props 应该根据不同的场景来进行渲染。
个人觉得,HOC 更倾向于封装一些复杂的操作,需要复用通用的业务状态和功能的时候使用。而 render props 比较适合抽离与业务无关但是和UI保存的状态有关的功能 (renderProps 内部管理的状态不方便从外部获取,因此只适合保存业务无关的数据,比如 Modal 显隐)。
RenderProps 工具库 react-powerplug
React PowerPlug 是利用 render props 进行更好状态管理的工具库。
在我们日常开发中,一个 Component 类中,可能有很多的 state 但是并不是每个状态都和有业务有关,比如:UI 的展示状态,受控组件的临时 value 等。
|
|
这时候我们就一些常用的状态管理封装成 render props 的形式。react-powerplug 就是提供这样工具的一个类库。这里简单看下几个功能,来帮助我们更好理解 render props 的应用。
Value
该方法是用来管理值操作的工具。
示例
|
|
Value 中,只存储一个属性 value,并赋初始值为 initial。
方法:set reset。
- set 回调函数触发后调用 setState 更新 value。
- reset 就是调用 set 并传入 this.props.initial 即可。
Active
这是一个内置鼠标交互监听的容器,监听了 onMouseUp 与 onMouseDown,并依此判断 active 状态。
示例
|
|
借助 Value 实现,巧妙的利用了 value,value 重命名为 active 且初始值为 false。增加了 bind 方法,借助 set 来更新状态。
|
|
其他功能就不一一展示了。
render props 嵌套问题
上面过,render props 有一个缺点当我们想要组合使用的时候,可能会遇到嵌套地狱问题。在 react-powerplug 中提供了 compose 函数,来解决这一问题。
|
|
社区也提供了 Epitath 工具来专门解决 render props 嵌套问题。细节就不看了。
React Hooks
React Hooks 是 React 16.7.0-alpha 版本推出的新特性。React Hooks 要解决的问题是状态共享,是继 render-props 和 higher-order components 之后的第三种状态共享方案,不会产生 JSX 嵌套地狱问题。之后介绍吧,现在还没空仔细体会呢。