1
头图

阅读前须知

流程图的内容90%来自于React技术揭秘一书,对其内容进行整理,方便正在学习源码的同学们能够系统性把每个关键知识点给串联起来,下面JPG图片比较模糊,图片宽高比较大,用手机打开pdf,观看起来也不方便,建议用电脑跳转下面各个pdf地址进行查看,带着问题来阅读。

React理念

1、react15与react > 16架构区别性?\
2、Fiber节点的组成?\
3、Fiber树的结构?何为深度优先遍历?\
4、Fiber工作原理(双缓存技术)?\
5、Fiber Mount与Update流程是怎么样?\
6、JSX与Fiber的区别?

pdf地址: bin-blog.oss-cn-shenzhen.aliyuncs.com/react/react…

React理念.jpg

React render阶段

1、进入render阶段前需要干什么(判断是否异步可中断更新)?\
2、Fiber节点的创建和Fiber树的构建如何开始(performUnitOfWork)?\
3、“递”阶段beginWork如何工作?\
4、‘归阶段’completeWork如何工作?\
5、如何判断是mount还是update?\
6、render阶段最终的产物是什么(effectList的生成、fiber节点的创建)?

pdf地址: bin-blog.oss-cn-shenzhen.aliyuncs.com/react/react…

React render阶段.jpg

React commit阶段

1、commit阶段如何开启(commitRoot方法)?\
2、before mutation阶段之前做了什么(flushPassiveEffects(),触发useEffect回调与其他同步任务)?\
3、rootFiber的effectTag不在effectList怎么办?\
4、before mutation阶段(执行Dom操作之前)做了什么?\
5、mutation阶段(执行Dom操作)做了什么?\
6、layout阶段(执行Dom操作后)做了什么?\
7、layout之后做了什么?\
8、最终产物是什么?

pdf地址: bin-blog.oss-cn-shenzhen.aliyuncs.com/react/react…

React commit阶段.jpg

React Diff算法

1、什么是diff算法?\
2、diff概念?\
3、diff算法发生的阶段?\
4、diff的预设限制?\
5、diff如何实现?

pdf地址: bin-blog.oss-cn-shenzhen.aliyuncs.com/react/react…

react diff算法.png

React 状态更新

1、触发状态更新关键链路?\
2、触发状态更新有哪些方法?\
3、HostRoot、ClassComponent的Update对象结构?\
4、ClassComponent、HostRoot的UpdateQueue结构?\
5、updateQueue的工作流程?\
6、调度优先级的过程?\
7、为什么componentWillXXX会触发多次,要加个unsafe_?\
8、如何保证Update不丢失?\
9、ReactDOM.render的流程?\
10、this.setState、this.forceUpdate的流程?\
11、React入口有哪三种模式?

pdf地址: bin-blog.oss-cn-shenzhen.aliyuncs.com/react/react…

React 状态更新.png

React Hook

1、一个极简的useState Hook的实现(强烈推荐,下面把这部分的代码贴出来了,对理解hook有帮助)\
2、Hook 的数据结构(类似updateQueue)\
3、mount/update的调起方法会以不同dispatcher区分\
4、useState与useReducer原理概览(对比上面极简useState hook的实现)\
5、usEffect(通过前几个流程图所讲flushPassiveEffects方法进行切入理解)概览\
6、useRef原理概览?ref的工作流程,render阶段做了什么?commit阶段做了什么?\
7、useMemo、useCallback原理概览,以及mount、update时两者的区别

pdf地址\
bin-blog.oss-cn-shenzhen.aliyuncs.com/react/react…

image.png

React Hooks.jpg

极简useState Hook的实现


// 首次render时是mount
let isMount = true;

// 通过workInProgressHook变量指向当前正在工作的hook
let workInProgressHook;

// App组件对应的fiber对象
const fiber = {
    // 保存该FunctionComponent对应的Hooks链表
    memoizedState: null,
    // 指向App函数
    stateNode: App
};

// APP组件
function App() {
    const [num, updateNum] = useState(0);
  
    console.log(`${isMount ? 'mount' : 'update'} num: `, num);
  
    return {
      click() {
        updateNum(num => num + 1);
      }
    }
}

// 模拟React开始调度更新
function schedule() {
    // 更新前将workInProgressHook重置为fiber保存的第一个Hook
    // 通过workInProgressHook变量指向当前正在工作的hook
    workInProgressHook = fiber.memoizedState;
    // 触发组件render
    fiber.stateNode();
    // 组件首次render为mount,以后再触发的更新为update
    isMount = false;
}

// 更新时底层驱动函数
function dispatchAction(queue, action) {
    // 创建update
    const update = {
      action, // 更新执行的函数 
      next: null // 与同一个Hook的其他更新形成链表
    }
  
    // 环状单向链表操作
    // 产生的update保存在useState对应的hook.queue
    if (queue.pending === null) {
      update.next = update;
    } else {
      update.next = queue.pending.next;
      queue.pending.next = update;
    }
    queue.pending = update;
  
    // 模拟React开始调度更新
    schedule();
}


function useState(initialState) {
    let hook;
  
    if (isMount) {
      // mount时需要生成hook对象
      // 保存update的queue,即上文介绍的queue
      hook = {
        queue: {
          pending: null
        },
        // 保存hook对应的state
        memoizedState: initialState,
        // 与下一个Hook连接形成单向无环链表
        next: null
      }
      // 将hook插入fiber.memoizedState链表末尾
      if (!fiber.memoizedState) {
        fiber.memoizedState = hook;
      } else {
        workInProgressHook.next = hook;
      }
       // 移动workInProgressHook指针
      workInProgressHook = hook;
    } else {
      // update时从workInProgressHook中取出该useState对应的hook
      hook = workInProgressHook;
      // 在组件render时,每当遇到下一个useState,我们移动workInProgressHook的指针。
      // 这样,只要每次组件render时useState的调用顺序及数量保持一致,那么始终可以通过workInProgressHook找到当前useState对应的hook对象。
      workInProgressHook = workInProgressHook.next;
    }
  
    let baseState = hook.memoizedState;
    if (hook.queue.pending) {
      // 获取update环状单向链表中第一个update
      let firstUpdate = hook.queue.pending.next;
  
      do {
        // 执行update action
        const action = firstUpdate.action;
        baseState = action(baseState);
        firstUpdate = firstUpdate.next;
        // 最后一个update执行完后跳出循环
      } while (firstUpdate !== hook.queue.pending.next)
      // 清空queue.pending
      hook.queue.pending = null;
    }
    // 将update action执行完后的state作为memoizedState
    hook.memoizedState = baseState;
  
    return [baseState, dispatchAction.bind(null, hook.queue)];
  }

前端晚间课
235 声望12 粉丝