最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 轻松掌握React Hooks底层实现原理

    正文概述 掘金(苏溪云)   2021-01-01   920

    由于最近业务较忙,2020年搞懂React原理系列文章最终篇直到现在才在业余时间抽空完成。之前在公司内部已有过一次PPT形式的分享,但经过一段时间对hooks的深度使用,对其又有了更深一些了解,故本次加上新内容并以文章形式再分享一次。

    持续一年阅读React源码和总结其核心原理,慢慢也有了一些心得:

    读懂源码只是第一步,弄懂其功能的代码实现方式。而再进一步是彻底搞懂其实现原理、思想,它通过什么方式实现了什么功能,带来了什么价值。

    不管它的底层代码如何改写,最终的目的都是为了实现某个功能。只要我们把其功能实现原理掌握,便可活学活用,结合业务让业务开发效率更高,或围绕业务做一些生产力工具。

    本文将重点讲useMemouseEffectuseState3个api,因为它们在日常开发中最常用。后面讲其他几个api。本次主要描述每个hook的功能和原理。

    基础知识

    任何一个hook的调用方式都是:

    输出 = hook函数(输入)
    

    一定会有输入和hook函数和输出。 而被调用的过程一般是2种:组件初始化和组件更新。

    UseMemo实现原理

    useMemo的功能是记忆某个结果,只有依赖项发生改变时才更新输出结果。

    输出结果 = useMemo(计算函数,依赖项)
    

    下方展示其在不同过程中useMemo内部实现原理。

    输入hook函数输出
    计算函数,依赖项useMemo计算结果

    组件初始化

    1. 执行计算函数,获取计算结果
    2. 缓存结果结果和依赖项
    3. 返回计算结果

    组件更新:

    if (依赖项和已缓存依赖项相同) {
        返回已缓存计算结果
    } else {
        执行计算函数,获取新计算结果
        缓存新计算结果和新依赖项
        返回新计算结果
    }
    
    Object.is('foo', 'foo');     // true
    Object.is(window, window);   // true
    
    Object.is('foo', 'bar');     // false
    Object.is([], []);           // false
    
    var foo = { a: 1 };
    var bar = { a: 1 };
    Object.is(foo, foo);         // true
    Object.is(foo, bar);         // false
    
    Object.is(null, null);       // true
    
    // Special Cases
    Object.is(0, -0);            // false
    Object.is(-0, -0);           // true
    Object.is(NaN, 0/0);         // true
    

    UseEffect实现原理

    useEffect(创建函数,依赖项)
    

    useEffect的主要功能是:

    组件加载后执行创建函数,创建函数执行后会返回一个销毁函数,在组件销毁前执行。

    若依赖项为数组且不为空,则依赖项改变时,会执行上一个销毁函数和重新执行创建函数。

    输入hook函数
    创建函数,依赖项useEffect

    useEffect直接被调用的过程是组件初始化和组件更新,其销毁函数被调用的过程是组件销毁。

    组件初始化

    1. 生成一个effect对象,包含创建函数
    2. 缓存effect和依赖项
    3. 当React进入提交阶段,执行effect中的创建函数,获取销毁函数。若销毁函数不为空,则将其放入effect。

    组件更新

    1. 生成一个effect对象, 包含创建函数
    2. 检查已缓存effect中是否有销毁函数,有的话则放入新effect对象
    3. 缓存effect
    4. 若依赖项和已缓存依赖项不同,则将hasEffect标记添加到effect,并缓存新依赖项
    5. 当React进入提交阶段:
    if (effect有hasEffect标记) {
        若effect中有销毁函数,则先执行销毁函数
        执行effect中的创建函数,获取销毁函数。若销毁函数不为空,则将其放入effect
    } 
    

    组件销毁

    1. 若effect中有销毁函数,则执行。

    UseState实现原理

    useState的功能是设置一个状态的初始值,并返回当前状态和设置状态的函数。

    [状态,设置状态函数] = useState(初始状态)
    
    输入hook函数输出
    初始状态useState状态,设置状态函数

    useState直接被调用的过程也是组件初始化和组件更新,其还有一个调用设置状态函数的过程。

    组件初始化

    1. 若初始状态为函数,则将函数执行结果设为当前状态。否则将初始状态设为当前状态。
    2. 生成设置状态函数
    3. 缓存当前状态和设置状态函数
    4. 返回当前状态

    组件更新

    1. 读取缓存状态和设置状态函数
    2. 返回缓存状态

    执行设置状态函数

    1. 更新缓存状态
    2. 触发React组件树更新
    3. 在下一次组件更新时,将返回已被更新的缓存状态

    useReducer

    useReducer的功能和原理与useState一致,区别在于useReducer使用函数管理状态,使用派发动作指令函数作为设置状态函数。Reducer概念可参看redux。

    [状态,派发动作指令函数]=useReducer(reducer函数,初始状态)
    

    UseCallback实现原理

    已缓存函数 = useCallback(待缓存函数,依赖项)
    

    useCallback的功能就是useMemo记忆函数一个封装,相比useMemo只是少套了一层函数:

    已缓存函数 = useMemo( () => 待缓存函数, 依赖项)
    

    不过React内部并没有用useMemo直接实现useCallback,而是用一套类似useMemo的代码实现。

    UseRef实现原理

    {current: 当前值} = useRef(初始当前值)
    

    useRef的功能是生成一个对象,结构是:{current: 当前值}, 对象一旦初始化,不会因为组件更新而改变。

    虽然对象初始化后不会因组件更新改变,但我们可以通过更改其current属性,当前值就相当于一个组件的变量,类似class组件的实例属性。

    useRef最常用的场景莫过于设置组件的ref。

    const container = useRef(null)
    return <div ref={container}></div>
    

    其实此处官网也有特别讲,div上的ref属性将触发设置container.current为dom对象。

    但我们也可以把useRef作为生成组件变量的方法灵活应用。

    输入hook函数输出
    初始当前值useRef{current: 当前值}

    组件初始化

    1. 生成对象: { current: 初始当前值 }
    2. 缓存对象
    3. 返回缓存对象

    组件更新

    1. 获取缓存对象
    2. 返回缓存对象

    UseImperativeHandle

    useImperativeHandle的功能被子组件使用,实现父组件调用子组件内部方法,一般与forwardRef一起使用。

    UseImperativeHandle实现原理与useEffect类似。

    UseLayoutEffect

    useLayoutEffect和useLayout的功能区别:

    useLayoutEffectuseLayout
    渲染到屏幕前执行渲染到屏幕后执行
    useLayoutEffect(() => {
       // 组件初始化或更新在渲染到屏幕前执行
       return () => {
         // 1. 组件卸载前执行 2. 执行下一个effect前执行
       } 
    }, )
    

    在跨年前完成2020搞懂React原理系列文章最后一篇,也是为了迎接即将到来的2021。

    在2021年,新的系列即将启航。不过在写新系列前,下一篇将先写微前端框架实现原理。

    祝大家新年快乐!


    起源地下载网 » 轻松掌握React Hooks底层实现原理

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元