完整高频题库仓库地址:https://github.com/hzfe/awesome-interview完整高频题库阅读地址:https://febook.hzfe.org/相关问题什么是ReactHooksReactHooks是如何实现的?使用ReactHooks时,需要注意什么?回答要点ClosureFiber链表Hooks是React16.8的新特性。它让您无需编写类即可使用状态和其他React功能。Hooks主要是用闭包来保存状态,用一个链表保存一系列的Hooks,把链表中的第一个Hook和Fiber关联起来。当Fiber树更新时,可以从Hooks中计算出最终的输出状态和执行相关的副作用。使用Hooks的注意事项:不要在循环、条件或嵌套函数中调用Hooks。只在React函数中调用Hooks。深入知识点1.ReactHooks模拟实现的简化实现本例为ReactHooks接口的简化模拟实现,可在实际操作中观察。其中,react.js文件模拟了useState和useEffect接口,其基本原理与react的实际实现类似。2.对比分析2.1stateHook模拟的useState的实现中,状态通过闭包保存在memoizedState[cursor]中。memoizedState是一个数组,可以依次保存多次hook调用产生的状态。letmemoizedState=[];letcursor=0;functionuseState(initialValue){//第一次调用时,传入的初始值作为状态,后续使用闭包中保存的状态letstate=memoizedState[光标]??初始值;//为游标做一个闭包缓存,这样调用setState时,操作的是正确的对应状态const_cursor=cursor;constsetState=(newValue)=>(memoizedState[_cursor]=newValue);//Cursor自增,对于下一个被调用的hook时,指的是memoizedState中的新位置cursor+=1;return[state,setState];}useState的实际实现经过多方面的综合考虑,React最终选择将Hooks设计为顺序结构,这也是为什么Hooks不能进行条件调用的原因。functionmountState(initialState:(()=>S)|S):[S,Dispatch>]{//创建一个Hook并将当前Hook添加到Hooks列表consthook=mountWorkInProgressHook();//如果初始值是一个函数,调用函数获取初始值if(typeofinitialState==="function"){initialState=initialState();}hook.memoizedState=hook.baseState=initialState;//创建一个链表来存储更新对象constqueue=(hook.queue={pending:null,dispatch:null,lastRenderedReducer:basicStateReducer,lastRenderedState:initialState,});//dispatch用于修改状态并将此更新添加到更新对象列表Inconstdispatch:Dispatch>=(queue.dispatch=(dispatchAction.bind(null,currentlyRenderingFiber,queue):any));return[hook.memoizedState,dispatch];}2.1副作用Hook模拟的UseEffect实现,同样使用memoizedState闭包存储依赖数组。依靠数组进行浅比较,默认的比较算法是Object.is。函数useEffect(cb,depArray){constoldDeps=memoizedState[cursor];让hasChange=true;if(oldDeps){//将传入的依赖数组与保存在闭包中的旧依赖数组进行比较,使用浅比较算法hasChange=depArray.some((dep,i)=>!Object.is(dep,oldDeps[i]));}if(hasChange)cb();memoizedState[cursor]=depArray;cursor++;}实际useEffect实现:functionmountEffect(create:()=>(()=>void)|void,deps:Array|void|null):void{returnmountEffectImpl(UpdateEffect|PassiveEffect,//fiberFlagsHookPassive,//hookFlagscreate,deps);}functionmountEffectImpl(fiberFlags,hookFlags,create,deps):void{//创建钩子consthook=mountWorkInProgressHook();constnextDeps=deps===未定义?空:部门;//设置workInProgresscurrentlyRenderingFiber的副作用标志。标志|=fiberFlags;//fiberFlags被标记为workInProgress//创建Effect,挂载到hook.memoizedStatehook.memoizedState=pushEffect(HookHasEffect|hookFlags,//hookFlags用于创建effectcreate,undefined,nextDeps);}3.Hooks和Fiber如何协同工作在了解如何工作之前,我们先看一下Hook和Fiber的一些结构定义:exporttypeHook={memoizedState:any,//lateststatevaluebaseState:any,//初始状态值baseQueue:Update|空,队列:UpdateQueue|null,//环形链表,存放多次调用hook产生的更新对象next:Hook|null,//next指针,下一个链表中的下一个Hook};exporttypeFiber={updateQueue:mixed,//存储Fiber节点相关的副作用链表memoizedState:any,//存储Fiber节点相关的状态值flags:Flags,//标识当前Fiber节点是否有副作用};与上一节的模拟实现不同,真实的Hooks是一个单链表结构,React按照Hooks的执行顺序依次将Hook节点添加到链表中。UseEffect以最常用的两个hooks为例,分析Hooks和Fiber是如何协同工作的。在每个状态Hook(如useState)节点中,所有的更新操作都会通过队列属性上的循环链表被记住,循环链表中的所有更新操作在更新阶段会依次执行,最后是最新的状态将被退回。stateHooks组成的链表的具体结构如下图所示:在每个sideeffectHook(比如useEffect)节点中,创建一个effect挂载到Hook的memoizedState中,添加到末尾循环链表,会保存到Fiber节点的updateQueue中,在commit阶段执行。side-effectHooks组成链表的具体结构如下图所示:参考WhyDoReactHooksRelyonCallOrder?Reacthooks:不是魔术,只是数组