render props
是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的技术。
简单来说,给一个组件传入一个prop
,这个props
是一个函数,函数的作用是用来告诉这个组件需要渲染什么内容,那么这个prop
就成为render prop
。
关于render props
的使用场景,我们先来看一段代码:
// A组件
class A extends Component {
state = { count: 0 };
add = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div className="a">
<h2>A组件</h2>
<button onClick={this.add}>add</button>
<B count={this.state.count} />
</div>
);
}
}
// B组件
class B extends Component {
render() {
return <h3 className="b">B组件,{this.props.count}</h3>;
}
}
// Father组件
export default class Father extends Component {
render() {
return (
<div className="father">
<h2>Father组件</h2>
<A />
</div>
);
}
}
最外层是一个Father
组件,Father
组件里面有个A
组件作为子组件。在A
组件的state
中,定义了count
计数值,并通过点击按钮来增加计数值。同时,在A
组件中,又嵌套了一个B
组件作为子组件,将A
组件中的count
计数值传给B
组件。B
组件通过props
接收到传来的count
,展示到页面上。各组件关系以及运行效果如下图所示:
以上代码虽然实现了效果:在A
组件中控制count
,在B
组件中展示count
值。但是,这种A
组件和B
组件的嵌套关系是固定的。
假如我们不希望B
作为A
的子组件,希望另一个C
组件来作为A
的子组件显示count
;或者,希望有另一个A
,但是这个A
里面的子组件不是B
而是组件C
。这时候,我们就需要修改A
组件中的代码,将B
组件换成C
组件,这显然不够高效,不够优雅。A
组件中的state
、控制state
中count
计数值的代码逻辑,都是相同的,我们却没有复用。
render props
解决了这类问题,能够封装固定的逻辑,动态地确定需要渲染的内容。可以这么理解:A
组件中的state
、控制state
中count
计数值的代码逻辑是不变的,改变的只是谁作为A
的子组件,有可能是B
,也有可能是C
。那么我们就可以在需要渲染子组件的地方,留一个空位,将来可以选择渲染B
,也可以选择渲染C
。这样,就复用了不变的逻辑,又能动态地选择要渲染的内容。
具体如何实现?来看如下一段的代码:
// A组件
class A extends Component {
state = { count: 0 };
add = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div className="a">
<h2>A组件</h2>
<button onClick={this.add}>add</button>
{this.props.render()}
</div>
);
}
}
// Father组件
export default class Father extends Component {
render() {
return (
<div className="father">
<h2>Father组件</h2>
<A render={() => <h3>h3标签</h3>} />
</div>
);
}
}
在Father
组件中,A
组件作为子组件,给A
组件传入了一个prop
,名为render
,类型是一个函数,函数的作用就是返回标签。在
A
组件中,通过this.props.render
拿到了传来的render
,但这只是一个函数,只用调用这个函数,才能获得返回值,所以通过{this.props.render()}
调用了传入的函数,返回一个标签。这样,
标签就被渲染到页面上了。
如上代码,A
组件的{this.props.render()}
就像是一个预留的空位,它具体是什么,取决于A
的父组件给A
传什么。这样,A
组件关于count
的逻辑不用改,只需更改给A
传的render
即可,A
组件动态渲染需要渲染的内容。
将上述用例用render props
修改完整:
// A组件
class A extends Component {
state = { count: 0 };
add = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div className="a">
<h2>A组件</h2>
<button onClick={this.add}>add</button>
{this.props.render(this.state.count)}
</div>
);
}
}
// B组件
class B extends Component {
render() {
return <h3 className="b">B组件,{this.props.count}</h3>;
}
}
// Father组件
export default class Father extends Component {
render() {
return (
<div className="father">
<h2>Father组件</h2>
<A render={count => <B count={count} />} />
</div>
);
}
}
Father
组件给A
组件传入了一个prop
,名为render
,类型是个函数。函数接收一个count
参数,返回B
组件,同时给B
组件传入了count
。A
组件内,通过{this.props.render(this.state.count)}
预留了一个空位,将state
内部的count
作为函数的参数,调用这个传来的函数。B
组件通过this.props.count
拿到了传来的count
,展示到了页面上。
若不希望用B
组件来展示,想用C
组件,那么只需在Father
组件中,修改A
组件的render
即可:
<A render={count => <C count={count} />} />
以上是本人学习所得之拙见,若有不妥,欢迎指出交流!
欢迎在我的博客上访问:
https://lzxjack.top/