术语“render prop”是指一种在react组件之间使用一个值为函数的prop共享代码的简单技术。
具有 render prop 的组件接受一个函数,该函数返回一个 React 元素并调用它而不是实现自己的渲染逻辑。
我们知道,组件是 React 代码复用的主要单元,但如何分享一个组件封装到其他需要相同 state 组件的状态或行为并不总是很容易。
如何使用render prop?
官网举了一个经典的跟踪 Web 应用程序中的鼠标位置的例子:
Render Props – React
我这里也举一个非常简单的使用render prop的例子,帮助大家更容易去理解。
首先,新建一个显示“Hello World”的组件ShowHello.js:
import React from 'react';
class ShowHello extends React.Component {
constructor(props) {
super(props);
this.state = {
greet:"Hello World"
}
}
render(){
return (
<p>{this.state.greet}</p>
)
}
}
export default ShowHello
现在我们有一个组件Page,想要获取组件ShowHello的greet此时的状态(即“Hello World”),我们常规的做法可以是:在ShowHello组件内部的渲染方法渲染 Page组件:
Page.js
import React from 'react';
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {
greet: this.props.greet //获取父组件(ShowHello)的prop
}
}
render(){
return (
<div>
<p>{this.state.greet}</p> //渲染
</div>
)
}
}
export default Page
ShowHello.js
import React from 'react';
import Page from './Page';
class ShowHello extends React.Component {
constructor(props) {
super(props);
this.state = {
greet:"Hello World"
}
}
render(){
return (
<div>
<Page greet={this.state.greet} /> //将greet作为prop传给子组件Page
</div>
)
}
}
export default ShowHello
这种方法适用于我们的特定用例,但我们还没有达到以可复用的方式真正封装状态或行为的目标。现在,每当我们想要状态用于不同的用例时,我们必须创建一个新的组件(本质上是另一个ShowHello组件,通过将prop传给另一个子组件),它专门为该用例呈现一些东西。
这也是 render prop 的来历:我们可以提供一个带有函数 prop 的ShowHello组件,它能够动态决定什么需要渲染,而不是将Page组件硬编码到ShowHello组件里,并有效地改变它的渲染结果。
import React from 'react';
class ShowHello extends React.Component {
constructor(props) {
super(props);
this.state = {
greet:"Hello World"
}
}
render(){
return (
<div>
{/* <Page greet={this.state.greet} /> */} //将prop方式换成render prop的方式
{this.props.render(this.state.greet)} //不同的组件共享同一个状态,且不需要创建
//一个新的ShowHello组件
</div>
)
}
}
export default ShowHello
import React from 'react';
import ShowHello from './ShowHello';
import Page from './Page';
class Home extends React.Component {
render(){
return (
<div>
<ShowHello render={greet => ( //通过render prop的方式决定哪个组件渲染使用此状态
<Page greet={greet}/>
)}/>
</div>
)
}
}
export default Home
现在,我们提供了一个 render
方法,让ShowHello组件能够动态决定什么需要渲染,而不是克隆ShowHello组件然后硬编码来解决特定的用例。如果存在其他组件使用该状态,那么只需要将render中的Page组件改成其他组件即可。
更具体地说,render prop 是一个用于告知组件需要渲染什么内容的函数 prop。
这项技术使我们共享状态或行为非常容易。要获得这个状态或行为,只要渲染一个带有render prop的组件就能够告诉它当前要渲染什么。
render prop并不是react的API,而是一种与高阶组件(HOC)类似的设计模式,ShowHello组件中传递的prop也不一定要是render,也可以是其他标识,如child(或其他自己想要的标识)。
import React from 'react';
import ShowHello from './ShowHello';
import Page from './Page';
class Home extends React.Component {
render(){
return (
<div>
<ShowHello child={greet => ( //prop可以为自己想要的标识,须传入一个函数
<Page greet={greet}/>
)}/>
</div>
)
}
}
export default Home
ShowHello内部的prop也相应变化
import React from 'react';
class ShowHello extends React.Component {
constructor(props) {
super(props);
this.state = {
greet:"Hello World"
}
}
render(){
return (
<div>
{this.props.child(this.state.greet)} //prop此时为child,切记此时child为函数
//上面相当于渲染成 <Page greet={this.state.greet} />
</div>
)
}
}
export default ShowHello
更容易理解的一种方式是,你可以认为现在prop传的不是具体某个状态,而是一个函数,函数体是要渲染(或者说使用共享状态)的组件,函数的参数为实际的传入渲染组件的state。
关键部分
<ShowHello child={greet => ( //prop为一个函数
<Page greet={greet}/>
)}/>
{this.props.child(this.state.greet)} //为函数传入共享状态