最后更新:2023-12-20
Render Props
整理自:https://zh-hans.reactjs.org/docs/render-props.html
术语 “render prop” 是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术。
具有 render prop 的组件接受一个返回 React 元素的函数,并在组件内部通过调用此函数来实现自己的渲染逻辑。
1 | <DataProvider render={data => ( |
使用 render prop 的库有 React Router、Downshift 以及 Formik。
1. 一个例子
一个组件<Mouse>,封装了所有关于监听 mousemove 事件和存储鼠标 (x, y) 位置的行为,但其仍不是真正的可复用。
举个例子,假设我们有一个 <Cat> 组件,它可以呈现一张在屏幕上追逐鼠标的猫的图片。我们或许会使用 <Cat mouse={{ x, y }} prop 来告诉组件鼠标的坐标以让它知道图片应该在屏幕哪个位置。
首先, 你或许会像这样,尝试在 <Mouse> 内部的渲染方法渲染 <Cat> 组件。这种方法适用于我们的特定用例,但我们还没有达到以可复用的方式真正封装行为的目标。现在,每当我们想要鼠标位置用于不同的用例时,我们必须创建一个新的组件(本质上是另一个 <MouseWithCat> ),它专门为该用例呈现一些东西.
这也是 render prop 的来历:相比于直接将 <Cat> 写死在 <Mouse> 组件中,并且有效地更改渲染的结果,我们可以为 <Mouse> 提供一个函数 prop 来动态的确定要渲染什么 —— 一个 render prop。
1 | class Cat extends React.Component { |
现在,我们提供了一个 render 方法 让 <Mouse> 能够动态决定什么需要渲染,而不是克隆 <Mouse> 组件然后硬编码来解决特定的用例。
更具体地说,render prop 是一个用于告知组件需要渲染什么内容的函数 prop。
这项技术使我们共享行为非常容易。要获得这个行为,只要渲染一个带有 render prop 的 <Mouse> 组件就能够告诉它当前鼠标坐标 (x, y) 要渲染什么。
关于 render prop 一个有趣的事情是你可以使用带有 render prop 的常规组件来实现大多数高阶组件 (HOC)。 例如,如果你更喜欢使用 withMouse HOC而不是 <Mouse> 组件,你可以使用带有 render prop 的常规 <Mouse> 轻松创建一个:
1 | // 如果你出于某种原因真的想要 HOC,那么你可以轻松实现 |
因此,你可以将任一模式与 render prop 一起使用。
2. 使用 Props 而非 render
重要的是要记住,render prop 是因为模式才被称为 render prop ,你不一定要用名为 render 的 prop 来使用这种模式。事实上, 任何被用于告知组件需要渲染什么内容的函数 prop 在技术上都可以被称为 “render prop”.
尽管之前的例子使用了 render,我们也可以简单地使用 children prop!
1 | <Mouse children={mouse => ( |
记住,children prop 并不真正需要添加到 JSX 元素的 “attributes” 列表中。相反,你可以直接放置到元素的内部!
1 | <Mouse> |
你将在 react-motion 的 API 中看到此技术。
由于这一技术的特殊性,当你在设计一个类似的 API 时,你或许会要直接地在你的 propTypes 里声明 children 的类型应为一个函数。
1 | Mouse.propTypes = { |
3. Render Props 会破坏React.PureComponent
如果你在 render 方法里创建函数,那么使用 render prop 会抵消使用 React.PureComponent 带来的优势。因为浅比较 props 的时候总会得到 false,并且在这种情况下每一个 render 对于 render prop 将会生成一个新的值。
例如,继续我们之前使用的 <Mouse> 组件,如果 Mouse 继承自 React.PureComponent 而不是 React.Component,我们的例子看起来就像这样:
1 | class Mouse extends React.PureComponent { |
在这样例子中,每次 <MouseTracker> 渲染,它会生成一个新的函数作为 <Mouse render> 的 prop,因而在同时也抵消了继承自 React.PureComponent 的 <Mouse> 组件的效果!
为了绕过这一问题,有时你可以定义一个 prop 作为实例方法,类似这样:
1 | class MouseTracker extends React.Component { |
如果你无法静态定义 prop(例如,因为你需要关闭组件的 props 和/或 state),则 <Mouse> 应该扩展 React.Component。





