本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
本文主要内容:介绍了render props的运用,使用render props代替HOC实现了代码复用
昨天写了一篇关于高阶组件转换原有组件实现代码复用的文章,今天随着课程进度的推进,了解到了render props这种更适合代码复用的办法,在此做一些总结介绍
名词解释
render props,在编写的实践理解后,就是将本组件的内容作为公用组件的函数props的返回值,然后使用公用组件提供的数据、函数这一类可复用的资源,实现同样或者类似的功能,也是相当于对本组件进行了一个加工。
props传入文本
所以我们先从基础的不是函数的props看起,下面是来自组件Example的代码,可以看到接收了props,并且将props中的name属性渲染了出来
import React from "react"
function Example(props) {
return <h1>Hi, {props.name}</h1>
}
export default Example
因此App.js中的代码就如下
function App() {
return (
<div>
<Example name={"Bob"} />
</div>
)
}
向props中传入了name属性,能获得下面的结果
props传入函数
传入一个文本已经是非常简单的事情了,但是如果我们传入的是一个函数呢
所以用<Example name={function() {return ("Bob")}} />传入一个函数
执行没有报错,但是浏览器的调试工具给我们报了错误
可以知道函数是不能被直接渲染出来的,我们应该接收的是函数的返回值
所以修改Example组件中的return <h1>Hi, {props.name}</h1>为return <h1>Hi, {props.name()}</h1>,添加上括号表示函数的调用,这样我们就得到了同样的效果
现在我们删掉Example组件中的h1,直接用div包裹props,如下
function Example(props) {
return (
<div>
{props.name()}
</div>
)
}
这时我们可以通过函数返回一个<h1>包裹的元素获得同样的效果,即使用如下代码
<Example name={function() {return (<h1>Hi, Bob</h1>)}} />
接下来我们要做的事可能有点难以理解。既然传入的是函数,那么它应该可以接受参数,所以我们在Example组件中,使用{props.name("Bob")}向函数中传入参数
然后在App.js的组件传入的函数props中接收props,如下
<Example name={function(props) {return <h1>Hi, {props}</h1>}} />
再给他们改个名,调整一下缩进,App组件中的Example如下
<Example render={
function(name) {
return <h1>Hi, {name}</h1>
}
} />
所以Example组件中接收的props也要修改为render,{props.render("Bob")}
这样我们就通过Example组件向App组件传递了数据,也就是丰富了App组件的内容、功能。
例子说明
仅仅通过上面最简单的演示应该还是很难理解,接下来就用昨天的例子来实现一下render props完成的代码复用
还是以Favorite为例,
获得Toggler组件
我们需要在Favorite中渲染Toggler组件,所以首先就是将withToggler.js转换为Toggler组件,也就是将原本输出的函数
export function withToggler(component) {
return function(props) {
return (
<Toggler component={component} {...props}/>
)
}
}
修改为输出组件export default Toggler
引入Toggler组件
第二步需要引入Toggler组件,并且将Favorite中原本的内容移入到props函数中,如下
function Favorite(props) {
return (
<Toggler render={function() {
return(
<div>
<h3>Click heart to favorite</h3>
<h1>
<span
onClick={props.toggle}
>
{props.on ? "❤️" : "♡"}
</span>
</h1>
</div>
)
}} />
)
}
这时还需要将这个props回到Toggler中渲染出来,所以修改Toggler.js中render()代码如下
render() {
return (
<div>
{/* {this.props.render()} */}
</div>
)
}
Toggler中传回数据与函数
接着我们要让Toggler提供state和toggle(),所以要在render()中传入,如下
render() {
return (
<div>
{this.props.render(this.state.on, this.toggle)}
</div>
)
}
可以看到通过this传回了两个需要的参数
Favorite使用传来的数据和函数
这时我们就可以在Favorite组件中接收了,使用如下代码
<Toggler render={function(on, toggle) {
return(
......
)
}} />
分别用on和toggle接收了state和函数
至于使用则是删掉原本的props,直接用on和toggle就可以了,如下
<Toggler render={function(on, toggle) {
return(
<div>
<h3>Click heart to favorite</h3>
<h1>
<span
onClick={toggle}
>
{on ? "❤️" : "♡"}
</span>
</h1>
</div>
)
}} />
所以同理可以使用箭头函数也对Menu进行类似修改
function Menu() {
return (
<Toggler render={
(on, toggle) => (
<div>
<button onClick={toggle}>{on ? "Hide" : "Show"} Menu </button>
<nav style={{display: on ? "block" : "none"}}>
<h6>Signed in as Coder123</h6>
<p><a>Your Profile</a></p>
<p><a>Your Repositories</a></p>
<p><a>Your Stars</a></p>
<p><a>Your Gists</a></p>
</nav>
</div>
)
} />
)
}
这样我们就用render props对HOCs进行了修改,同样实现了代码复用