react-hook原理

demo

诸位请看下面这块熟悉的代码

ts 复制代码
const Component = () => {
    const [count,setCount] = useState(0)
    const [name,setName] = useState('')
    const add = () => {
        setCount(count+1)
        setCount(count+1)
        setCount(val=>val+1)
    }
    useEffect(()=>{
        setName(`第${count}个`)
    },[count])
    return (
      <>
        <div>
          {count}
        </div>
         <div>
          {name}
        </div>
        <button onClick={add}>增加</button>
      </>
    )
}

背景

  • 类组件:通过属性维护着自身的状态、函数、ui。通过生命周期函数将状态的变更和逻辑代码结合
  • 函数组件:通过传入的属性决定状态和ui

很明显,当我们希望count变化时,只执行与count相关的逻辑(add)。如果是类组件的话,我们需要在componentDidUpdate生命周期中写入setCount逻辑。而name变化时需要执行的逻辑(updateName)也需要写入componentDidUpdate,反复在componentDidUpdate写入逻辑,耦合度的变高会导致可读性、可复用性、可测试性降低。

那怎么办,函数组件又没有状态管理能力。

所以React Hooks来了,它的特点如下:

  1. 在函数式组件的基础上引入了state,并让state的每一个属性自治,而不是放入一个state对象中管理
  2. 引入useEffect,使得state的更新与更新逻辑可一对一的关联,锁定依赖的影响范围
  3. 引入useMemo、useCallBack,使得组件的性能优化更方便的实现了(各位可以想想类组件想实现状态的缓存是不是会很麻烦)
  4. 去处了没必要的模板代码,比如类函数的构造函数、生命周期函数
  5. 依赖的影响范围锁定之后,逻辑不会在生命周期函数中冗合,代码的复用性、可测试性提高了。

请看文章一开始的demo,count控制着一个ui,而count的更新逻辑add能很简单的和count的变化绑定起来,而且代码层级扁平化,没有生命周期函数的嵌套,没有state嵌套count,易于阅读,易于测试,易于控制范围。

原理

react hooks中引入了很多的hook,useStateuseEffectuseMomeuseCallbackuseRef

他们都有其各自的作用,其底层原理各不相同,这篇文章会以useStateuseEffect抛砖引玉,各位甚至可以自己给react-hooks添加属于自定义的hook。

前置知识补充:

  1. 函数组件在react底层以fiberNode形式存在,它有以下属性
  • tag:指定组件是类组件/函数组件/原生dom标签
  • key:唯一键
  • children:子代组件集合
  • sibling:本组件的下一个兄弟组件,主要用于将树的层级结构打平,不然树的层级过深会导致函数调用栈会爆满
  • memorizedState:存储组件的状态,比如函数组件的hook链表
  • updateQueue:组件状态改变后的回调函数,比如useEffect、useMemo的函数
  1. 函数组件在状态变化后会重新执行自身函数

以文章开头的demo为例,初次执行这个函数组件时,即mount阶段,执行到第一个useState第二个useState后,这两个hook会以链表的形式存储在fiberNode的memorizedState中,如下图所示。

执行到useEffect后,这个hook会存入hook链表中,然后将自身的effect放入fiberNode的updateQueue中,如下图

当我们点击增加按钮时,会执行setCount(count+1)setCount(count+1)setCount(val=>val+1),这三个函数会以循环链表的形式存储在count的useState的pending

每次执行useState返回的reducer时,即setCountsetName等,会触发一个scheduleWork函数,该函数最终会去触发组件的重新渲染。

这里会有一个问题:短时间内触发多次setCount就会触发多次scheduleWork,那是不是就会短时间内触发多次重渲染呢?

结论:react会将多个scheduleWork合并做批量更新操作,并且会根据很多因素(比如任务队列)来调度这些更新任务,各位对这里有兴趣的,可以自行查看源码。

触发更新后,函数式组件会重新执行,进入update阶段,当再次执行到第一个useState第二个useState后,依旧会将他们放入hook链表中。

当再次执行到useEffect后,会执行上一次的useEffect的effect中的return函数,然后比较更新前后的依赖是否更新了,如果依赖更新了,则这本次的effect打上更新flag,存入fiberNode的updateQueue中;否则不打上更新flag,再存入updateQueue中。

然后更新ui

然后执行firberNode的updateQueue中有更新flag的effect。

好啦,抛砖引玉弄完啦!

看到这里的各位看官,麻烦点个赞赞吧!

相关推荐
伍哥的传说38 分钟前
鸿蒙系统(HarmonyOS)应用开发之手势锁屏密码锁(PatternLock)
前端·华为·前端框架·harmonyos·鸿蒙
yugi98783840 分钟前
前端跨域问题解决Access to XMLHttpRequest at xxx from has been blocked by CORS policy
前端
浪裡遊1 小时前
Sass详解:功能特性、常用方法与最佳实践
开发语言·前端·javascript·css·vue.js·rust·sass
旧曲重听12 小时前
最快实现的前端灰度方案
前端·程序人生·状态模式
默默coding的程序猿2 小时前
3.前端和后端参数不一致,后端接不到数据的解决方案
java·前端·spring·ssm·springboot·idea·springcloud
夏梦春蝉2 小时前
ES6从入门到精通:常用知识点
前端·javascript·es6
马特说2 小时前
React金融数据分析应用性能优化实战:借助AI辅助解决18万数据量栈溢出Bug
react.js·金融·数据分析
归于尽2 小时前
useEffect玩转React Hooks生命周期
前端·react.js
G等你下课2 小时前
React useEffect 详解与运用
前端·react.js
我想说一句2 小时前
当饼干遇上代码:一场HTTP与Cookie的奇幻漂流 🍪🌊
前端·javascript