写点什么

9.hooks 源码 (想知道 Function Component 是怎样保存状态的嘛)

用户头像
全栈潇晨
关注
发布于: 2021 年 03 月 04 日

人人都能读懂的 react 源码解析(大厂高薪必备)

9.hooks 源码(想知道 Function Component 是怎样保存状态的嘛)

视频课程 &调试 demos

​ 视频课程的目的是为了快速掌握 react 源码运行的过程和 react 中的 scheduler、reconciler、renderer、fiber 等,并且详细 debug 源码和分析,过程更清晰。

​ 视频课程:进入课程

​ demos:demo

课程结构:

  1. 开篇(听说你还在艰难的啃react源码)

  2. react心智模型(来来来,让大脑有react思维吧)

  3. Fiber(我是在内存中的dom)

  4. 从legacy或concurrent开始(从入口开始,然后让我们奔向未来)

  5. state更新流程(setState里到底发生了什么)

  6. render阶段(厉害了,我有创建Fiber的技能)

  7. commit阶段(听说renderer帮我们打好标记了,映射真实节点吧)

  8. diff算法(妈妈再也不担心我的diff面试了)

  9. hooks源码(想知道Function Component是怎样保存状态的嘛)

  10. scheduler&lane模型(来看看任务是暂停、继续和插队的)

  11. concurrent mode(并发模式是什么样的)

  12. 手写迷你react(短小精悍就是我)

hook 调用入口

​ 在 hook 源码中 hook 存在于 Dispatcher 中,Dispatcher 就是一个对象,不同 hook 调用的函数不一样,全局变量 ReactCurrentDispatcher.current 会根据是 mount 还是 update 赋值为 HooksDispatcherOnMount 或 HooksDispatcherOnUpdate

ReactCurrentDispatcher.current =   current === null || current.memoizedState === null//mount or update  ? HooksDispatcherOnMount	: HooksDispatcherOnUpdate;  
复制代码


const HooksDispatcherOnMount: Dispatcher = {//mount时  useCallback: mountCallback,  useContext: readContext,  useEffect: mountEffect,  useImperativeHandle: mountImperativeHandle,  useLayoutEffect: mountLayoutEffect,  useMemo: mountMemo,  useReducer: mountReducer,  useRef: mountRef,  useState: mountState,  //...};
const HooksDispatcherOnUpdate: Dispatcher = {//update时 useCallback: updateCallback, useContext: readContext, useEffect: updateEffect, useImperativeHandle: updateImperativeHandle, useLayoutEffect: updateLayoutEffect, useMemo: updateMemo, useReducer: updateReducer, useRef: updateRef, useState: updateState, //...};
复制代码

hook 数据结构

​ 在 FunctionComponent 中,多个 hook 会形成 hook 链表,保存在 Fiber 的 memoizedState 的上,而需要更新的 Update 保存在 hook.queue.pending 中

const hook: Hook = {  memoizedState: null,//对于不同hook,有不同的值  baseState: null,//初始state  baseQueue: null,//初始queue队列  queue: null,//需要更新的update  next: null,//下一个hook};
复制代码

下面来看下 memoizedState 对应的值

  • useState:例如const [state, updateState] = useState(initialState)memoizedState等于state 的值

  • useReducer:例如const [state, dispatch] = useReducer(reducer, {});memoizedState等于state 的值

  • useEffect:在 mountEffect 时会调用 pushEffect 创建 effect 链表,memoizedState就等于 effect 链表,effect 链表也会挂载到 fiber.updateQueue 上,每个 effect 上存在 useEffect 的第一个参数回调和第二个参数依赖数组,例如,useEffect(callback, [dep]),effect 就是{create:callback, dep:dep,…}

  • useRef:例如useRef(0),memoizedState就等于{current: 0}

  • useMemo:例如useMemo(callback, [dep])memoizedState等于[callback(), dep]

  • useCallback:例如useCallback(callback, [dep])memoizedState等于[callback, dep]useCallback保存callback函数,useMemo保存callback的执行结果

useState&useReducer

之所以把 useState 和 useReducer 放在一起,是因为在源码中 useState 就是有默认 reducer 参数的 useReducer。

  • useState&useReducer 声明

  • mount 阶段

  • update 阶段

  • 执行阶段

useEffect

  • 声明

  • mount 阶段

  • update 阶段

  • 执行阶段

useRef

​ sring 类型的 ref 已经不在推荐使用,ForwardRef 只是把 ref 通过传参传下去,createRef 也是{current: any 这种结构,所以我们只讨论 function 或者{current: any}的 useRef

//createRef返回{current: any}export function createRef(): RefObject {  const refObject = {    current: null,  };  return refObject;}//ForwardRef第二个参数是ref对象let children = Component(props, secondArg);
复制代码
  • 声明阶段

  • mount 阶段

  • update 阶段

useMemo&useCallback

  • 声明阶段

  • mount 阶段

  • update 阶段

function updateMemo<T>(  nextCreate: () => T,  deps: Array<mixed> | void | null,): T {  const hook = updateWorkInProgressHook();//获取hook  const nextDeps = deps === undefined ? null : deps;  const prevState = hook.memoizedState;
if (prevState !== null) { if (nextDeps !== null) { const prevDeps: Array<mixed> | null = prevState[1]; if (areHookInputsEqual(nextDeps, prevDeps)) {//浅比较依赖 return prevState[0];//没变 返回之前的状态 } } } const nextValue = nextCreate();//有变化重新调用callback hook.memoizedState = [nextValue, nextDeps]; return nextValue;}
function updateCallback<T>(callback: T, deps: Array<mixed> | void | null): T { const hook = updateWorkInProgressHook();//获取hook const nextDeps = deps === undefined ? null : deps; const prevState = hook.memoizedState;
if (prevState !== null) { if (nextDeps !== null) { const prevDeps: Array<mixed> | null = prevState[1]; if (areHookInputsEqual(nextDeps, prevDeps)) {//浅比较依赖 return prevState[0];//没变 返回之前的状态 } } }
hook.memoizedState = [callback, nextDeps];//变了重新将[callback, nextDeps]赋值给memoizedState return callback;}
复制代码


用户头像

全栈潇晨

关注

还未添加个人签名 2021.02.17 加入

还未添加个人简介

评论

发布
暂无评论
9.hooks源码(想知道Function Component是怎样保存状态的嘛)