关于useState

函数组件

function App() {

  const [num, updateNum] = useState(0);

  window.updateNum = updateNum;

  return num;

}

调用window.updateNum(1)可以将视图中的0更新为1

对于如下函数组件

function App() {

  const [num, updateNum] = useState(0);

 

  function increment() {

    setTimeout(() => {

      updateNum(num + 1);

    }, 1000);

  }

 

  return

{num}

;

}

点击5次 结果仍为1


hook如何保存数据

FunctionComponent的render本身只是函数调用。

那么在render内部调用的hook是如何获取到对应数据呢?

比如:

useState获取state

useRef获取ref

useMemo获取缓存的数据

答案是:

每个组件有个对应的fiber节点(可以理解为虚拟DOM),用于保存组件相关信息。

每次FunctionComponent render时,全局变量currentlyRenderingFiber都会被赋值为该FunctionComponent对应的fiber节点。

所以,hook内部其实是从currentlyRenderingFiber中获取状态信息的。


多个hook如何获取数据

我们知道,一个FunctionComponent中可能存在多个hook,比如:

function App() {

  // hookA

  const [a, updateA] = useState(0);

  // hookB

  const [b, updateB] = useState(0);

  // hookC

  const ref = useRef(0);

 

  return

;

}

那么多个hook如何获取自己的数据呢?

答案是:

currentlyRenderingFiber.memoizedState中保存一条hook对应数据的单向链表。

对于如上例子,可以理解为:

const hookA = {

  // hook保存的数据

  memoizedState: null,

  // 指向下一个hook

  next: hookB

  // ...省略其他字段

};

hookB.next = hookC;

currentlyRenderingFiber.memoizedState = hookA;

当FunctionComponent render时,每执行到一个hook,都会将指向currentlyRenderingFiber.memoizedState链表的指针向后移动一次,指向当前hook对应数据。

这也是为什么React要求hook的调用顺序不能改变(不能在条件语句中使用hook) —— 每次render时都是从一条固定顺序的链表中获取hook对应数据的。

useState执行流程

我们知道,useState返回值数组第二个参数为改变state的方法。

在源码中,他被称为dispatchAction。

每当调用dispatchAction,都会创建一个代表一次更新的对象update:

const update = {

  // 更新的数据

  action: action,

  // 指向下一个更新

  next: null

};

对于如下例子

function App() {

  const [num, updateNum] = useState(0);

 

  function increment() {

    updateNum(num + 1);

  }

 

  return

{num}

;

}

调用updateNum(num + 1),会创建:

const update = {

  // 更新的数据

  action: 1,

  // 指向下一个更新

  next: null

  // ...省略其他字段

};

你可能感兴趣的:(关于useState)