什么是渲染道具,它与高阶组件有什么不同?
Posted
技术标签:
【中文标题】什么是渲染道具,它与高阶组件有什么不同?【英文标题】:What's render props, how is it different from high order components? 【发布时间】:2018-07-07 14:15:50 【问题描述】:似乎render props 到目前为止还没有得到足够的关注,但是,它被著名的 React 库广泛使用,例如 react-router 4
、react motion
等。而且 React 站点也有一个专门的部分,任何理由这种出现的模式,与众所周知的 HOC(高阶组件)模式相比如何?
【问题讨论】:
【参考方案1】:为我的研究留下答案,非常欢迎不同的答案和讨论!
HOC 借鉴了High Order Function 的概念:
高阶函数(也称为泛函、泛函形式或函子)是至少执行以下操作之一的函数:
将一个或多个函数作为参数(即过程参数), 返回一个函数作为其结果。[有争议 - 讨论]
HOC
高阶组件 (HOC) 是 React 中用于重用组件逻辑的高级技术。
源自Gist。
这个模式是关于STATIC组合的。核心/可重用逻辑封装在 HOC 中,而将活动部分留给组件。
以 react 路由器中的withRouter 为例:
withRouter 将在渲染时将更新的匹配、位置和历史道具传递给包装的组件。
// 这绕过了 shouldComponentUpdate
withRouter(connect(...)(MyComponent))
现在你得到一个增强的 MyComponent 回来,它有由路由器 HOC 传递的 history, match, location, ...connectProps, ...ownProps
的 props。
一种常见的方法是
compose(
connect( ... ),
enhance( ... ),
withRouter( ... ),
lifecycle( ... ),
somethingElse( ... )
)(MyComponent);
最重要的是,您可以使用compose utility 无限组合这些 HOC,以获得组件的最终增强版本,并且您的组件将从 HOC 返回的新组件中获得有关 redux 存储、反应路由器等的知识.
这种方法的缺点是:
组件的行为是在运行时之前定义的,因此失去了 react 渲染生命周期的能力,比如你不能这样做:
compose(
this.state.shouldConnect && connect( ... ),
this.state.shouldEnhance && enhance( ... ),
this.state.shouldWithRouter && withRouter( ... ),
...
)(MyComponent);
因为state
/props
在您的代码运行之前不可用。
间接和命名冲突。
将 HOC 与 ES6 类一起使用会带来许多与 mixin 与 createClass 相同的问题,只是重新安排了一下。
HOC 引入了很多仪式,因为它们包装组件并创建新组件,而不是混入现有组件中。
渲染道具
渲染道具是组件用来知道要渲染什么的函数道具。
首先被react-motion 采用,早在Dan's Gist 首次提交redux 前几周看到。
这个模式是关于DYNAMIC组合的。核心/可重用逻辑保留在组件中,而移动部分作为回调属性传递。
您可以通过渲染道具创建 HOC。
还是以withRouter为例:
const withRouter = Component =>
const C = props =>
const wrappedComponentRef, ...remainingProps = props;
return (
<Route
render=routeComponentProps => (
<Component
...remainingProps
...routeComponentProps
ref=wrappedComponentRef
/>
)
/>
);
;
...
return hoistStatics(C, Component);
;
反之则不然。
<Connect render=connectPropsMergedWithState =>
<Enhance render=enhancePropsMergedWithState =>
<WithRouter render=routerPropsMergedWithState =>
<Lifecycle render=lifecyclePropsMergedWithState =>
<SomethingElse render=somethingElsePropsMergedWithState =>
...
/>
...
/>
...
/>
...
/>
...
/>
虽然看起来不太好,但收获不少。
-
它具有更好的明确性,因为我们可以看到作为参数传递给渲染道具的确切内容。
因为 1,它使我们免于潜在的道具碰撞。
它是动态的,我们可以传递任何我们喜欢的东西(包括
state
/props
)来渲染道具。
众所周知的缺点是performance optimization is tricky,因为要接收的道具被推迟到运行时。过早进行优化可能不是一个好主意,但这可能完全是另一个话题。
如果你同意 react router 从 3 到 4 的方向移动,render props 可能是你的问题。
参考资料:
-
https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce
https://reactrocket.com/post/turn-your-hocs-into-render-prop-components
【讨论】:
我非常震惊 a) 通常过分热心的模组并没有将问题标记为过于广泛,并且 b) 这篇出色的文章没有任何支持。编辑:啊,我刚刚注意到你写了这个问题并自己回答了;为什么不写一篇博文呢? @ParkerAult 如您所料,如果这个答案能有所帮助,那就太好了,几天前我也有同样的问题,它被标记为太宽泛,因为我最初的尝试是寻找一个答案,我做了一些研究并将其留在这里以获得更好的答案,我仍然认为这是一个合理的问题,有很多来自不同人的好想法:) 我同意这是一个合理的问题,因为它似乎是一种越来越流行的设计模式。我是否正确地说“渲染道具”模式与“作为儿童的功能”相同,因为儿童充当常规道具并且可以传递任何数据(在这种情况下为函数),因此可以调用就像渲染道具一样。 @tomhughes 当然,它们完全一样。更重要的是,正如您所说,它们实际上是带有反应糖的非常通用的设计模式。 HOC 只是类似于 *Decorator*/mixin 模式的高阶函数,而渲染道具(子函数)是向组件客户端提供控制反转的回调。以上是关于什么是渲染道具,它与高阶组件有什么不同?的主要内容,如果未能解决你的问题,请参考以下文章