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。

好啦,抛砖引玉弄完啦!

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

相关推荐
Martin -Tang30 分钟前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发31 分钟前
解锁微前端的优秀库
前端
王解1 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
老码沉思录1 小时前
写给初学者的React Native 全栈开发实战班
javascript·react native·react.js
老码沉思录1 小时前
React Native 全栈开发实战班 - 第四部分:用户界面进阶之动画效果实现
react native·react.js·ui
我不当帕鲁谁当帕鲁1 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂2 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成4 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽5 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习