为什么要学习ReactHooks原理?最后,趋势已经从原来的类组件转向功能组件。这是设计模式和心智模型层面的最新创新。所以,只要说到React的能力,面试的时候肯定会被问到。到ReactHooks的原理。再者,从实用的角度,了解ReactHooks的原理,对我们日常的开发调试大有裨益;我们可以意识到,ReactHooks其实并不是什么黑魔法,而我们在开发中遇到的奇葩问题,只不过是我们还没有掌握ReactHooks,不需要使用一些取巧的方法来解决而已。useState/useReduceruseState和useReducer都是关于状态值的提取和更新。本质上没有区别。在实现上,useState可以说是useReducer的简化版,其背后使用的是同一套逻辑。ReactHooks是如何保存状态的在React官方文档中提到,ReactHooks保存状态的位置其实和class组件的保存位置是一样的;翻阅源码后,发现这个说法是正确的,但并不全面:两者的状态值是相同的,挂载在组件实例对象FiberNode的memoizedState属性中。两者保存状态值的数据结构完全不同;class组件直接将state属性挂载的开发者自定义对象保存到memoizedState属性中;而ReactHooks是用一个链表来保存状态的,memoizedState属性save其实就是这个链表的头指针。我们来看看这个链表的节点长什么样子——Hook对象://react-reconciler/src/ReactFiberHooks.jsexporttypeHook={memoizedState:any,//最新状态值baseState:any,//初始状态值,比如`useState(0)`,初始值为0baseUpdate:Update|null,queue:UpdateQueue|null,//暂时保存对state值的操作,更确切地说是A链表数据结构中的指针next:Hook|null,//指向下一个链表节点};官方文档一直强调ReactHooks的调用只能放在函数组件/自定义Hooks函数体的顶层,因为我们只能通过Hooks调用的顺序关联到实际保存的数据结构:PS:虽然上面以useState和useReducer为例是一致的,但实际上所有的ReactHooks都是以链表这种方式保存的。ReactHooks如何更新状态如果你熟悉useStateAPI,我们都知道如何更新状态:const[name,setName]=useState('')setName('张三')然后,用于更新的函数useState(以下简称dispatcher)返回的状态,其运行原理是什么?我们每次调用dispatcher的时候,并不会立即修改state值(是的,state值的更新是异步的),而是创建一个修改操作——挂载在对应Hook对象的queue属性上的链表添加一个新节点:下次执行该功能组件,再次调用useState时,React会根据挂载在每个Hook上的更新操作链表,计算出最新的state值。你可能会好奇,为什么要保存所有的更新操作,只保存最新的更新操作不就可以了吗?你可能会这样想,你可能忘记了useState支持这种语法:const[name,setName]=useState('')setName(name=>name+'a')setName(name=>name+'b')setName(name=>name+'c')//可以在下次执行时得到name的最新状态值为'abc'。下面根据mount和update两个组件生命周期来讲解useEffect的执行原理:mount阶段:mountEffect在函数组件的函数体中根据顺序调用的useEffect语句构建链表挂载到FiberNode中.updateQueue,链表节点数据结构为:consteffect:Effect={tag,//用于标识依赖是否发生变化create,//用户使用useEffect销毁的函数体,//执行后生成上面的函数体去除了副作用Functiondeps,//dependencylistnext:(null:any),};组件渲染完成后,遍历链表执行。update阶段:updateEffect也依次调用useEffect语句,判断此时传入的依赖列表和链表节点Effect.deps中保存的是否一致(基础数据类型的值是否相同;对象的引用相同),如果一致,则在Effect.tag标签上使用NoHookEffect。在执行阶段,每个组件渲染完成后,会进入useEffect的执行阶段:functioncommitHookEffectList():遍历链表,遇到Effect.tag标记为NoHookEffect的节点则跳过。如果Effect.destroy是函数类型,需要执行清除副作用的函数(至于Effect.destroy从何而来,稍后会讲到)执行Effect.create,并将执行结果保存到Effect.destroy(如果开发者没有配置return,结果会是undefined,也就是说开发者认为当前useEffect代码段没有需要清除的sideeffect);请注意,由于闭包,Effect.destroy实际上可以在Effect.create函数的范围内访问this变量。需要注意的重点是:先清除上一轮的副作用,再执行本轮的效果。其他ReactHooksApi其他ReactHooksApi,其实原理都差不多:使用链表数据结构来维护全局状态;判断依赖决定是否更新state等,这里不再赘述。小结本文用更精炼的语言阐述了ReactHooks的原理。目的是让读者有一个感性的认识,方便采访;但实际上,ReactHooks还是有很多实现细节的。如果你有兴趣,请阅读源代码。这里。