Problem
借用react
官網(wǎng)的例子悦即,當(dāng)我們需要一個(gè)<Mouse>
組件的時(shí)候彼宠,我們直接去實(shí)現(xiàn)它浴捆,我們初始的目標(biāo)是為了實(shí)現(xiàn)一個(gè)移動(dòng)鼠標(biāo)同時(shí)可以顯示鼠標(biāo)位置睛驳,通過封裝可以實(shí)現(xiàn)烙心,如下:
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}>
{/* ...但我們?nèi)绾武秩?<p> 以外的東西? */}
<p>The current mouse position is ({this.state.x}, {this.state.y})</p>
</div>
);
}
}
class MouseTracker extends React.Component {
render() {
return (
<div>
<h1>移動(dòng)鼠標(biāo)!</h1>
<Mouse />
</div>
);
}
}
但是實(shí)現(xiàn)了上面的<MouseTracker>
組件后膜廊,需求又變了,我們需要實(shí)現(xiàn)的不只是顯示鼠標(biāo)位置了淫茵,同時(shí)需要在該位置上顯示一個(gè)<Cat>
組件爪瓜,這意味著我們需要再次卻封裝一個(gè)新的組件<MouseWithCat>
,在這個(gè)組件里面包含了<Cat position={x: this.state.x, y: this.state.y} />
匙瘪,其目的就是為了<Cat>
組件可以使用<Mouse>
組件內(nèi)部的狀態(tài)铆铆,但是這就需要我們必須去再次封裝一個(gè)新的組件,如果最后需要的有各式各樣的要求丹喻,針對(duì)每一個(gè)要求都去實(shí)現(xiàn)一個(gè)新的組件薄货,而且這些組件都充斥著大量重復(fù)的代碼,這樣的工作是無意義的碍论,且會(huì)帶來代碼的冗長谅猾。
// 這里我們實(shí)現(xiàn)了<MouseWithCat>,那如果我們還需要<MouseWithDog>呢鳍悠?是不是還要再把這一套代碼再寫一遍税娜?這明顯是重復(fù)的工作
class MouseWithCat 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}>
{/*
我們可以在這里換掉 <p> 的 <Cat> ......
但是接著我們需要?jiǎng)?chuàng)建一個(gè)單獨(dú)的 <MouseWithSomethingElse>
每次我們需要使用它時(shí),<MouseWithCat> 是不是真的可以重復(fù)使用.
*/}
<Cat mouse={this.state} />
</div>
);
}
}
Solution (render props)
我們可以提供一個(gè)帶有函數(shù) prop
的 <Mouse>
組件贼涩,它能夠動(dòng)態(tài)決定什么需要渲染的巧涧,而不是將 <Cat>
或是 <Dog>
硬編碼到 <Mouse>
組件里,并有效地改變它的渲染結(jié)果遥倦,這樣就避免了大量重復(fù)的代碼
// 首先修改<Mouse>組件的代碼谤绳,在最后render的內(nèi)容區(qū)域留一塊用來render將要傳進(jìn)來的內(nèi)容
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 }} />
);
}
}
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>
);
}
}
class MouseTracker extends React.Component {
render() {
return (
<div>
<h1>移動(dòng)鼠標(biāo)!</h1>
// 使用時(shí)就在<Mouse>組件上設(shè)一個(gè)函數(shù)形式的prop,當(dāng)然這個(gè)屬性名字可以隨便取袒哥,只要和前面對(duì)應(yīng)上就OK缩筛,特殊情況,把這個(gè)的名字設(shè)為children的時(shí)候堡称,可以寫成這樣的形式
<Mouse>
{
mouse => (<Cat mouse={mouse} />)
}
</Mouse>
// 上下兩種情況對(duì)于prop是children的情況是等價(jià)的
<Mouse render={mouse => (<Cat mouse={mouse} />)}/>
</div>
);
}
}