术语 “render prop” 是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术
什么是Render Props
官网是这样介绍的:
The term “render prop” refers to a simple technique for sharing code between React components using a prop whose value is a function.
大概意思是:给组件添加一个props值是函数,这个函数可以在组件渲染(render)的时候调用,那这个组件是干啥用的呢?就是为了给原有组件“注入”其它组件的代码。
在什么情况下使用Render Props
a render prop is a function prop that a component uses to know what to render.
翻译过来就是说,这个render prop就是让组件知道自己渲染什么东西。
如果你一个组件不知道自己渲染什么东西,或者说你一个组件的基础功能是提供”可变数据源“,具体展示UI可以从外部注入,那么就可以用这个技术了。
更具体地说,render prop 是一个用于告知组件需要渲染什么内容的函数 prop。
使用 Render Props 来解决横切关注点(Cross-Cutting Concerns)
组件是 React 代码复用的主要单元,但如何分享一个组件封装到其他需要相同 state 组件的状态或行为并不总是很容易。
可变数据源组件
例如:现在 组件封装了所有关于监听 mousemove 事件和存储鼠标 (x, y) 位置的行为,在这里,我们说Mouse组件提供“可变数据源”,但是它并不知道自己要渲染什么,它只是一个基础数据的提供者。
class Mouse extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
{/*
Instead of providing a static representation of what <Mouse> renders,
use the `render` prop to dynamically determine what to render.
*/}
{this.props.render(this.state)}
</div>
);
}
}
假设我们有一个 组件,它可以呈现一张在屏幕上追逐鼠标的猫的图片,之后可能还有类似渲染dog,pig需求。 这也是 render prop 的来历:我们提供一个带有函数 prop 的 组件,它能够动态决定什么需要渲染的。
被注入UI组件
这个Cat组件就是我们希望渲染在页面的UI了。
class Cat extends React.Component {
render() {
const mouse = this.props.mouse;
return (
<img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
);
}
}
Mouse组件Render Props渲染Cat
class MouseTracker extends React.Component {
render() {
return (
<div>
<h1>移动鼠标!</h1>
<Mouse render={mouse => (
<Cat mouse={mouse} />
)}/>
</div>
);
}
}
首先我们知道组件的鼠标的位置,但其他组件cat, dog, pig也需要知道鼠标位置来根据坐标显示不同的图片,这时就需要将的state共享到其他组件,就可以使用Render Props。
这项技术使我们共享行为非常容易。要获得这个行为,只要渲染一个带有 render prop 的 组件就能够告诉它当前鼠标坐标 (x, y) 要渲染什么。
关于 render prop 一个有趣的事情是你可以使用带有 render prop 的常规组件来实现大多数高阶组件 (HOC)。 例如,如果你更喜欢使用 withMouse HOC而不是 组件,你可以使用带有 render prop 的常规 轻松创建一个:
将 Render Props 与 React.PureComponent 一起使用时要小心
如果使用render Props技术的组件(也就是有一个render函数属性的组件)是继承自React.PureComponent的,例如如果 Mouse 继承自 React.PureComponent,那么在props的浅比较看来,新老props总是不一样的,那么就会每次都重新渲染,性能开销比较大。
在这样例子中,每次 <MouseTracker> 渲染,它会生成一个新的函数作为 <Mouse render> 的 prop,因而在同时也抵消了继承自 React.PureComponent 的 组件的效果!
为了绕过这一问题,有时你可以定义一个 prop 作为实例方法,类似这样:
class MouseTracker extends React.Component {
// 定义为实例方法,`this.renderTheCat`始终
// 当我们在渲染中使用它时,它指的是相同的函数
renderTheCat(mouse) {
return <Cat mouse={mouse} />;
}
render() {
return (
<div>
<h1>Move the mouse around!</h1>
<Mouse render={this.renderTheCat} />
</div>
);
}
}
参考文章
官网 Render Props
React 重温之Render Props
React 中的 Render Props
React组件设计实践总结04 - 组件的思维