前言
自己对render props\hoc\hook的区别和适用场景都不怎么了解
在写文章前的个人理解:
render props->体现组件之间的父子关系,非常灵活
hoc ->更加突出工厂模式
hooks -> 让函数组件更加贴近类组件
render props
第一次看官方文档的时候,觉得render props
就是渣男制造机啊哈哈。至于为什么用“渣男”这个词来描述组件,因为“渣男”普适性高,独立性强,所以可以更好的复用,请看下方例子有更加传神的描述。
初步了解
官方例子是要实现一个这样的效果,猫随着鼠标动
demoMouse组件
<div className="Mouse" onMouseMove={this.handleMouseMove}>
<p>position is ({x},{y})</p>
<Cat x={x} y={y}/>
</div>
代码中有一个<Mouse>
组件跟踪鼠标位置,将位置信息传给<Cat>
,然后<Cat>
组件根据Mouse传给他的信息进行显示。但是这里,Cat是Mouse的子组件,就显得不够分离了。如果你要改成狗、改成猪可以新增一个prop传图片,但是如果想鼠标经过的位置弄一些炫酷的特效,是不是就得重新写一遍获取鼠标的逻辑了~(我们设计一个组件的时候,要提高他的复用性,就要让他能处理更多的场景,所以他的功能必须更加的独立、单一,才能更好的将组件们组合起来。)
好在render props就提供了一个简单的复用的思路:Cat还是依赖Mouse里state的变化,state还是要传给Cat,但是经过render props一整,二者如胶似漆的状态就变得更加分离,Mouse拥有了渣男属性。对于Mouse组件来说,之前
“我心中只有你,我的state的改变是为你而存在”
的忠犬形象颠覆了,但现在
“我也可以和更多类型的组件一起为开发者大人干活了,小Cat你只是我的备胎之一哦~~”
但悲剧的事,对于Cat组件来说,还是那个傻瓜组件,一行代码都不用改,仍然纯洁得一塌糊涂!!
把Mouse和Cat写在同一个层级,将Cat作为render props传给Mouse组件,如下:
// App.js
function App() {
return (
<div className="App">
{/* 这里的函数prop名字叫啥都行!不是说非得叫render */}
<Mouse render={(props)=><Cat {...props}/>}/>
</div>
);
}
// Mouse.js
handleMouseMove(e){
const {clientX,clientY}=e
this.setState({
x:clientX,
y:clientY
})
}
// 省略了很多代码
<div className="Mouse" onMouseMove={this.handleMouseMove}>
<p>position is ({x},{y})</p>
{this.props.render({x,y})}
</div>
render props是一个用于告知组件用于渲染什么内容的函数prop,他把组件可以动态渲染的地方暴露给外部,你不用再关注组件的内部实现,只要把数据通过函数传出去就好。
render props有什么好处?坏处?具体应用
相关阅读:Comparison: HOCs vs Render Props vs Hooks
这篇文章提到(我以为michael jackson是作者瞎掰的,居然确有其人):
render props让组件知道他自己里边渲染了什么??其实也就是让开发者知道包裹的这个组件里边具体包含了什么组件,传了什么props进去,而不是像之前传统写法那样对于里面的组件一无所知,增强了代码的可读性。
如果传多个renderProps,明显可读性增加了不少/
// Login.jsx
<LoginForm
renderButton={(DefaultButton, buttonProps) => (
<DefaultButton {...buttonProps}>{value}</DefaultButton>
)}
renderInput={
...
}
renderCheckBox={
...
}
/>
与几个小兄弟一起为开发者大人干活,干杯!
与Hooks结合
export default function Mouse(props){
const [pos,setPosition]=useState({x:0,y:0})
return (
<div className="Mouse" onMouseMove={(e)=>setPosition({x:e.clientX,y:e.clientY})}>
<p>position is ({pos.x},{pos.y})</p>
{props.render({x:pos.x,y:pos.y})}
</div>)
}
妈呀,代码一下子清爽好多!不用再写什么class ... extends React
blabla的东西了。
扩展:hooks好处?坏处?注意事项
好处:代码少了!可以用functional组件代替class了。不用bind this了(一直以来的诟病)!!(官方文档提到:class写的组件不能很好的压缩,使热重载不稳定--但不知道为什么,希望可以得到解答)
注意事项:只能在函数最外层调用hook,不要在循环、条件判断或子函数中调用。
弊端:墙裂推荐阅读-> React Hooks 你真的用对了吗?
以下概括:
- hook依赖的数组元素过多,难以维护,比如:
const refresh = useCallback(() => {
// ...
}, [name, searchState, address, status, personA, personB, progress, page, size]);
- useMemo、useCallback的滥用。比如对于:
const resolveValue=useMemo(()=>{return compute(a,b)},[a,b])
如果compute()
是一个非常简单的计算,使用useMemo
可能会带来比直接计算更大的开销。所以在进行大型计算时使用会更好。第二个是,resolveValue
值是否为对象类型,如果是对象类型因为比较的是引用,每次函数调用都会产生新的引用,所以这里用useMemo
就比较合适了,但如果是原始值的时候就没什么必要,上文作者建议用useMemo
来保持值的一致性。
再加上HOC
如果这种组件要用的地方很多,想扩展更多的功能,比如说这个例子中处理props,或进行渲染劫持
export default function withMouse(Component) {
return class extends React.Component {
handleProps(){
// ...do something to props
}
render() {
const newProps=this.handleProps()
return (
this.props.logIn
?
(<Mouse render={positions => (
<Component {...newProps} {...positions} />
)}/>)
: null
);
}
}
}
hoc好处坏处??
好处:处理场景适用性很广,更加体现工厂模式。
坏处:嵌套的问题比较讨厌,不好调试。对props的劫持,不小心就污染了包裹的组件。
结尾
强烈推荐阅读这篇文章!!!Comparison: HOCs vs Render Props vs Hooks。尤其是文章后半部分,作者从可读性、复用性、定制化、调试、可测性和性能几个角度来比较这三个小兄弟,最后从开发者角度上来看render props比hooks略胜一筹,把hoc远远的甩在后边。
hoc当然没有他说的那么难用,还是看场景,起码hoc可以做很多render props不能做的事情。当然hooks也无法代替他, 推荐阅读:什么是 HOC 适合做而 React Hooks 不适合的场景? - 程墨Morgan的回答 - 知乎
网友评论