react native前端面试题详解让前端飞

深入理解render props

2020-01-10  本文已影响0人  mytac

前言

自己对render props\hoc\hook的区别和适用场景都不怎么了解

在写文章前的个人理解:

render props->体现组件之间的父子关系,非常灵活
hoc ->更加突出工厂模式
hooks -> 让函数组件更加贴近类组件

render props

第一次看官方文档的时候,觉得render props就是渣男制造机啊哈哈。至于为什么用“渣男”这个词来描述组件,因为“渣男”普适性高,独立性强,所以可以更好的复用,请看下方例子有更加传神的描述。

初步了解

官方例子是要实现一个这样的效果,猫随着鼠标动

demo

Mouse组件

<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是作者瞎掰的,居然确有其人):

A Render Prop is a function prop that a component uses to know what to render.

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 你真的用对了吗?

以下概括:

  1. hook依赖的数组元素过多,难以维护,比如:
const refresh = useCallback(() => {
  // ...
}, [name, searchState, address, status, personA, personB, progress, page, size]);
  1. useMemo、useCallback的滥用。比如对于:
const resolveValue=useMemo(()=>{return compute(a,b)},[a,b]) 

如果compute()是一个非常简单的计算,使用useMemo可能会带来比直接计算更大的开销。所以在进行大型计算时使用会更好。第二个是,resolveValue值是否为对象类型,如果是对象类型因为比较的是引用,每次函数调用都会产生新的引用,所以这里用useMemo就比较合适了,但如果是原始值的时候就没什么必要,上文作者建议用useMemo来保持值的一致性。

再加上HOC

如果这种组件要用的地方很多,想扩展更多的功能,比如说这个例子中处理props,或进行渲染劫持

推荐阅读-> 深入理解 React 高阶组件

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的回答 - 知乎

最后请大家关注我的订阅号获得更加及时的推送~

那屋水泡
上一篇 下一篇

猜你喜欢

热点阅读