什么是 Render Props?
就是组件上名为 render 的 prop,该属性可以动态决定要渲染的内容
具体的写法如下:
<Component render={data => (
<h1>Hello {data.target}</h1>
)}/>
也就是说,在 Component 组件内部渲染的时候,会调用 this.props.render 方法获取外部传过来的 jsx,来改变自己真正 render 时的效果。所以 render prop 是一个用于告知组件需要渲染什么内容的函数 prop。
为什么要用 Render Props?
目的就是为了组件的复用,把无关视图的逻辑抽象出来,例如下面的代码封装了鼠标追踪器的逻辑,能够根据鼠标的位置来实时更新坐标:
import React from 'react'
class MouseTracker extends React.Component {
state = {
x: 0,
y: 0,
}
handleMouseMove = event => {
this.setState({
x: event.clientX,
y: event.clientY,
})
}
render() {
return (
<div onMouseMove={this.handleMouseMove} >
{this.props.render(this.state)}
</div>
)
}
}
export default MouseTracker
这个组件的作用就是输出鼠标坐标的值,并不关心当用户拿到了坐标值,如何做展示。所以把视图层的渲染内容交给了 render 属性处理:
import MouseTracker from './MouseTracker'
function Tracker() {
return (
<MouseTracker
render={props => (
<div style={{ height: '100vh' }}>
{props.x},{props.y}
</div>
)}
/>
)
}
export default Tracker
使用 Render Props 的注意事项
如果像上面写的一样,在 render 方法里面创建 render 函数的话,每次渲染都会创建一个新的函数,如果你的类继承自 PureComponent 的话,其实是没有起到作用的:
import MouseTracker from './MouseTracker'
class Tracker extends React.PureComponent {
render() {
return (
<MouseTracker render={props => (
<div style={{ height: '100vh' }}>
{props.x},{props.y}
</div>
)}
/>
)
}
}
所以建议改成下面这个样子:
class Tracker extends React.PureComponent {
renderView(props) {
return (
<div style={{ height: '100vh' }}>
{props.x},{props.y}
</div>
)
}
render() {
return <MouseTracker render={this.renderView} />
}
}
和高阶函数 HOC 的对比
逻辑复用还有一种方式就是高阶函数(HOC),是可以达到相同的效果的,代码如下:
import React from 'react'
const withMouse = Component => {
return class extends React.Component {
state = { x: 0, y: 0 }
handleMouseMove = event => {
this.setState({
x: event.clientX,
y: event.clientY,
})
}
render() {
return (
<div onMouseMove={this.handleMouseMove}>
<Component {...this.props} {...this.state} />
</div>
)
}
}
}
export default withMouse
使用的时候也很简单,谁想获得高阶函数注入的 x 和 y 属性的话,就用 withMouse 包裹一下就好了:
import withMouse from './withMouse'
function Tracker(props) {
return (
<div style={{ height: '100vh' }}>
{props.x},{props.y}
</div>
)
}
export default withMouse(Tracker)
但是这种写法总是没有 Render Props 那么直观,万一原来的组件也有 x 和 y 属性的话,就被覆盖了。当然 HOC 也有其使用场景,例如一个通用的高阶函数,用于判断组件的访问权限,有权限则显示,无权限则跳转。