You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
这个代码有一个问题,在执行 useState 的时候每次都会 var _val = initialValue,初始化数据;
于是我们可以用闭包的形式来保存状态。
constMyReact=(function(){// 定义一个 value 保存在该模块的全局中letvaluereturn{useState(initialValue){value=value||initialValuefunctionsetState(newVal){value=newVal}return[value,setState]}}})()
functiondispatchAction<A>(fiber: Fiber, queue: UpdateQueue<A>, action: A) {//... 省略验证的代码constalternate=fiber.alternate;/* 这其实就是判断这个更新是否是在渲染过程中产生的,currentlyRenderingFiber只有在FunctionalComponent更新的过程中才会被设置,在离开更新的时候设置为null,所以只要存在并更产生更新的Fiber相等,说明这个更新是在当前渲染中产生的,则这是一次reRender。所有更新过程中产生的更新记录在renderPhaseUpdates这个Map上,以每个Hook的queue为key。对于不是更新过程中产生的更新,则直接在queue上执行操作就行了,注意在最后会发起一次scheduleWork的调度。 */if(fiber===currentlyRenderingFiber||(alternate!==null&&alternate===currentlyRenderingFiber)){didScheduleRenderPhaseUpdate=true;constupdate: Update<A> = {expirationTime: renderExpirationTime,action,next: null,};
if (renderPhaseUpdates === null) {renderPhaseUpdates=newMap();}
const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
if (firstRenderPhaseUpdate === undefined) {renderPhaseUpdates.set(queue,update);} else {// Append the update to the end of the list.letlastRenderPhaseUpdate=firstRenderPhaseUpdate;while(lastRenderPhaseUpdate.next!==null){lastRenderPhaseUpdate=lastRenderPhaseUpdate.next;}
lastRenderPhaseUpdate.next = update;
}}else{constcurrentTime=requestCurrentTime();constexpirationTime=computeExpirationForFiber(currentTime,fiber);constupdate: Update<A>={
expirationTime,
action,next: null,};flushPassiveEffects();// Append the update to the end of the list.constlast=queue.last;if(last===null){// This is the first update. Create a circular list.update.next=update;} else {constfirst=last.next;if(first!==null){// Still circular.update.next=first;}
last.next = update;
}queue.last=update;scheduleWork(fiber,expirationTime);}}
useState 解析
useState 使用
通常我们这样来使用 useState 方法
这个代码有一个问题,在执行 useState 的时候每次都会 var _val = initialValue,初始化数据;
这样在每次执行的时候,就能够通过闭包的形式 来保存 value。
不过这个还是不符合 react 中的 useState。因为在实际操作中会出现多次调用,如下。
因此我们需要在改变 useState 储存状态的方式
useState 模拟实现
因此当重新渲染 App 的时候,再次执行 useState 的时候传入的参数 kevin , 0 也就不会去使用,而是直接拿之前 hooks 存储好的值。
hooks 规则
为什么不可以?
我们来看下
useEffect 解析
useEffect 使用
useEffect 的模拟实现
useEffect 注意事项
依赖项要真实
刚开始使用 useEffect 的时候,我只有想重新触发 useEffect 的时候才会去设置依赖
那么也就会出现如下的问题。
希望的效果是界面中一秒增加一岁
其实你会发现 这里界面就增加了 一次 年龄。究其原因:
**在第一次渲染中,
age
是0
。因此,setAge(age+ 1)
在第一次渲染中等价于setAge(0 + 1)
。然而我设置了0依赖为空数组,那么之后的 useEffect 不会再重新运行,它后面每一秒都会调用setAge(0 + 1) **也就是当我们需要 依赖 age 的时候我们 就必须再 依赖数组中去记录他的依赖。这样useEffect 才会正常的给我们去运行。
所以我们想要每秒都递增的话有两种方法
方法一:
方法二
注:上面我们模拟的 useState 并没有做这个处理 后面我会讲解源码中去解析。
useEffect 只运行了一次,通过 useState 传入函数的方式它不再需要知道当前的
age
值。因为 React render 的时候它会帮我们处理这正是
setAge(age => age + 1)
做的事情。再重新渲染的时候他会帮我们执行这个方法,并且传入最新的状态。所以我们做到了去时刻改变状态,但是依赖中却不用写这个依赖,因为我们将原本的使用到的依赖移除了。(这句话表达感觉不到位)
接口无限请求问题
刚开始使用 useEffect 的我,在接口请求的时候常常会这样去写代码。
然后得意洋洋的刷新界面,发现 Network 中疯狂循环的请求接口,导致页面的卡死。
究其原因是因为在依赖中,我们通过接口改变了状态 props 的更新, 导致重新渲染组件,导致会重新执行 useEffect 里面的方法,方法执行完成之后 props 的更新, 导致重新渲染组件,依赖项目是对象,引用类型发现不相等,又去执行 useEffect 里面的方法,又重新渲染,然后又对比,又不相等, 又执行。因此产生了无限循环。
Hooks 源码解析
该源码位置:
react/packages/react-reconciler/src/ReactFiberHooks.js
mountState 源码
dispatchAction 源码
mountReducer 源码
useState
不过就是个语法糖,本质其实就是useReducer
注:这里仅是 react 源码,至于重新渲染这块 react-dom 还没有去深入了解。
更新:
分两种情况,是否是 reRender,所谓
reRender
就是说在当前更新周期中又产生了新的更新,就继续执行这些更新知道当前渲染周期中没有更新为止他们基本的操作是一致的,就是根据
reducer
和update.action
来创建新的state
,并赋值给Hook.memoizedState
以及Hook.baseState
。注意这里,对于非
reRender
得情况,我们会对每个更新判断其优先级,如果不是当前整体更新优先级内得更新会跳过,第一个跳过得Update
会变成新的baseUpdate
,他记录了在之后所有得Update,即便是优先级比他高得,因为在他被执行得时候,需要保证后续的更新要在他更新之后的基础上再次执行,因为结果可能会不一样。来源
preact 中的 hooks
注意:这里的替代是指如果不用 react 的话,可以使用这个。而不是取代。
useState 源码解析
useReducer 源码解析
getHookState 方法
invokeOrReturn 方法
总结
使用 hooks 几个月了。基本上所有类组件我都使用函数式组件来写。现在 react 社区的很多组件,都也开始支持hooks。大概了解了点重要的源码,做到知其然也知其所以然,那么在实际工作中使用他可以减少不必要的 bug,提高效率。
最后
参考:
The text was updated successfully, but these errors were encountered: