useState()
函数是 React 中的一个 Hook,用于在函数式组件中引入状态。该函数的完整实现涉及到一些 React 内部的机制,下面我们来一步步解读。
首先,useState()
函数的实现是基于 useStateImpl
函数的。具体来说,useState()
函数会调用 useStateImpl
函数,并且将组件的状态初始化值作为参数传递给它:
function useState(initialState) {
// 调用 useStateImpl 函数,并且将 initialState 作为参数传递给它
return useStateImpl(initialState);
}
然后,我们来看一下 useStateImpl
函数的完整实现。下面是 useStateImpl
函数的源码,带有注释解释每一步的细节:
// React 内部维护的变量,表示当前正在渲染的组件
let currentlyRenderingComponent;
// React 内部维护的变量,表示当前正在渲染的 hook 的索引
let currentHookIndex = 0;
function useStateImpl(initialState) {
// 获取当前正在渲染的组件
const component = currentlyRenderingComponent;
// 获取当前正在渲染的 hook 的索引
const index = currentHookIndex;
// 如果是初次渲染,则从组件的 memoizedState 中获取该 hook 的 state
if (component.memoizedState === null) {
// 创建一个数组用于存储所有的 hooks
component.memoizedState = [initialState, function setState(newState) {
// 更新 state
component.memoizedState[index][0] = newState;
// 触发重新渲染
component.update();
}];
}
// 获取该 hook 的 state 和 setState 函数
const [state, setState] = component.memoizedState[index];
// 更新当前正在渲染的 hook 的索引
currentHookIndex++;
// 返回 state 和 setState 函数
return [state, setState];
}
对上面代码的解释:
-
React 内部维护了两个全局变量,分别是
currentlyRenderingComponent
和currentHookIndex
。其中currentlyRenderingComponent
表示当前正在渲染的组件,currentHookIndex
表示当前正在渲染的 hook 在该组件中的索引。 -
useStateImpl
函数首先获取当前正在渲染的组件和正在渲染的 hook 的索引。这里需要注意的是,组件对象中有一个名为memoizedState
的属性,它用于存储该组件中所有的 hook 的状态和 setState 函数。如果是初次渲染,memoizedState
的值为 null,我们需要为它创建一个数组,数组的第一个元素是状态的初始值,第二个元素是 setState 函数。 -
setState
函数是一个闭包函数,它能够访问到当前正在渲染的组件对象、当前正在渲染的 hook 的索引和状态的初始值。在setState
函数中,我们更新了 hook 的状态,并且触发重新渲染。 -
接下来,我们获取该 hook 的状态和 setState 函数,并且更新当前正在渲染的 hook 的索引。最后,返回状态和 setState 函数的数组。
总的来说,useState()
函数的实现原理是基于 React 内部维护的 memoizedState
属性来实现的。当组件初次渲染时,memoizedState
的值为 null,我们需要为它创建一个数组,数组的第一个元素是状态的初始值,第二个元素是 setState 函数。在组件重新渲染时,我们可以直接从 memoizedState
中获取该 hook 的状态和 setState 函数,无需重新创建。这种实现方式可以保证 hook 的状态和 setState 函数能够正确地关联到组件上,同时也能够避免状态和函数被重复创建。