如果您检查React github 上的实现,您会注意到useState 只是使用基本reducer 调用useReducer:
export function useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
return useReducer(
basicStateReducer,
(initialState: any),
);
}
所以寻找useReducer 实现,我们看到setter 函数是dispatch 函数,它根据我们当前所处的生命周期而变化
export function useReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
...
// dispatch depends on lifecycle
return [..., dispatch];
}
}
您可以看到完整的useReducer 实现here。
对于详细的实现,你应该尝试Build your own React,这最终会导致这个钩子的简化版本:
function useState(initial) {
const oldHook =
wipFiber.alternate &&
wipFiber.alternate.hooks &&
wipFiber.alternate.hooks[hookIndex];
const hook = {
state: oldHook ? oldHook.state : initial,
queue: []
};
const actions = oldHook ? oldHook.queue : [];
actions.forEach(action => {
hook.state = action(hook.state);
});
const setState = action => {
hook.queue.push(action);
wipRoot = {
dom: currentRoot.dom,
props: currentRoot.props,
alternate: currentRoot
};
nextUnitOfWork = wipRoot;
deletions = [];
};
wipFiber.hooks.push(hook);
hookIndex++;
return [hook.state, setState];
}
简单来说:每个钩子都保存在“React钩子数组”中(这就是为什么调用顺序是必不可少的,因为钩子保存在数组的索引中 - 请参阅钩子规则),并且根据钩子的索引,每当调用它时都会改变与当前组件关联的状态对象。