react hooks的更新外围,其实是一个链表的钩子。

目前能够确定,useRef和useState相似,每一个useState/useRef都能够了解为一个钩子,钩子(指针)存储在workInProgressHook中

能够回顾一下useRef的源码:react hooks实质摸索 - useRef源码详解

初始化workInProgressHook代码如下(中文正文为笔者增加的正文,英文正文为源代码里的正文)

function mountWorkInProgressHook() {  // 新建链表结点  var hook = {    memoizedState: null,    baseState: null,    baseQueue: null,    queue: null,    next: null  };    // workInProgressHook能够了解为链表的指针  // 个别状况:指针指的不是链表的结尾  if (workInProgressHook !== null) {    // 把新的hook赋值给以后workInProgressHook的next    workInProgressHook.next = hook;        // 让以后的指针指向下一个钩子    workInProgressHook = workInProgressHook.next  }  // 非凡状况:指针指的是null,阐明链表未建设。  if (workInProgressHook === null) {     // 让指针指向hook       workInProgressHook = hook;          // 这里先不去管他,currentlyRenderingFiber$1应该是优化渲染局部的     currentlyRenderingFiber$1.memoizedState = workInProgressHook;  }  // 返回指针  return workInProgressHook;}

总结来说,等于是把链表的next指向一个新的hook,同时返回了这个链表的表尾。
以上就是初始化useRef/useState干的事件。

接下来看更新时,useRef/useState干了什么:
因为代码比拟长,能够先看一个步骤图理解一下步骤拆解

上面看源码(中文正文为笔者增加的正文,英文正文为源代码里的正文):

function updateWorkInProgressHook() {  // This function is used both for updates and for re-renders triggered by a  // render phase update. It assumes there is either a current hook we can  // clone, or a work-in-progress hook from a previous render pass that we can  // use as a base. When we reach the end of the base list, we must switch to  // the dispatcher used for mounts.  var nextCurrentHook;   // 这里在workInProgressHook之外,引入了一个新的概念:currentHook  // 然而这个概念能够不必管,因为这是fiber的概念。咱们本次不须要晓得fiber的概念   if (currentHook === null) {    var current = currentlyRenderingFiber$1.alternate;    if (current !== null) {      nextCurrentHook = current.memoizedState;    } else {      nextCurrentHook = null;    }  } else {    nextCurrentHook = currentHook.next;  }  // 来到咱们相熟的workInProgressHook  var nextWorkInProgressHook;  // 以下这块代码,是为了初始化nextWorkInProgressHook  // 非凡状况:链表结尾。如果以后的指针指向为空,阐明为结尾。留神这里判断的是workInProgressHook  if (workInProgressHook === null) {    // 为什么这么赋值,也跟fiber无关。能够先不论      nextWorkInProgressHook = currentlyRenderingFiber$1.memoizedState;  } else {    // 如果不是链表结尾,那么会让nextWorkInProgressHook等于以后链表指针的next,很好了解    nextWorkInProgressHook = workInProgressHook.next;  }  // 这个模块是为了让workInProgressHook失常地指向下一个链表节点  // 失常状况:初始化nextWorkInProgressHook后,nextWorkInProgressHook不为空  if (nextWorkInProgressHook !== null) {    // 这部分逻辑就是失常将workInProgressHook指针指向下一个元素    // There's already a work-in-progress. Reuse it.    workInProgressHook = nextWorkInProgressHook;        // nextWorkInProgressHook在这个办法里不再用到,然而一个全局变量,其余中央可能用到。    nextWorkInProgressHook = workInProgressHook.next;    currentHook = nextCurrentHook;  } else {    // 非凡状况:初始化nextWorkInProgressHook后,nextWorkInProgressHook依然为空    // 可能有两种状况:    //   1.workInProgressHook为空(代表链表为空),currentlyRenderingFiber$1.memoizedState为空    //   2.workInProgressHook不为空,以后指针指向了链表的尾部,所以workInProgressHook.next为空,导致nextWorkInProgressHook为空。    // 不论链表为空,还是指向了结尾,形象意义上都是指向了链表结尾。    // 这两种状况,最初都执行了workInProgressHook = newHook;            // 这一块都是解决fiberNode,能够不论    // Clone from the current hook.    if (!(nextCurrentHook !== null)) {      {        throw Error( "Rendered more hooks than during the previous render." );      }    }    currentHook = nextCurrentHook;    var newHook = {      memoizedState: currentHook.memoizedState,      baseState: currentHook.baseState,      baseQueue: currentHook.baseQueue,      queue: currentHook.queue,      next: null    };    // 解决链表为空的状况    // 这里要留神,如果nextWorkInProgressHook不为空,那么workInProgressHook也肯定不为空。所以这里隐含了一个条件:    // workInProgressHook和nextWorkInProgressHook都为空。    if (workInProgressHook === null) {      // 这里稍稍改写下,把间断赋值分成了两局部            // 链表为空,就须要把第一个元素赋值给指针,让链表指针失常      // This is the first hook in the list.      workInProgressHook = newHook;            // fiber相干      currentlyRenderingFiber$1.memoizedState = workInProgressHook;    } else {    // 以后指针指向了链表的尾部的状况          // 这里做了简略的改写      // Append to the end of the list.      workInProgressHook.next = newHook;            // 能够看到,workInProgressHook = newHook是必然执行的。也要留神,这里是在两个else里。      workInProgressHook = newHook;    }  }  return workInProgressHook;}