useState
基本使用
function HelloWorld(){
const [data,setData]=useState(0)
return <div>
<h1>{data}</h1>
<button onClick={()=>{
setData((data)=>{
return data+=1
})
}}>自增+</button>
</div>
}
useState顺序分解
useState---hooks钩子
useState: function (initialState) {
currentHookNameInDev = 'useState'
mountHookTypesDev()
var prevDispatcher = ReactCurrentDispatcher$1.current
ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV
try {
return mountState(initialState)
} finally {
ReactCurrentDispatcher$1.current = prevDispatcher
}
},
逐条分析:
1. currentHookNameInDev 当前hook名字在dev环境
2. function mountHookTypesDev() {
{
var hookName = currentHookNameInDev
if (hookTypesDev === null) { //初始化执行这里
hookTypesDev = [hookName]
} else {
hookTypesDev.push(hookName)
}
}
}
3. ReactCurrentDispatcher$1.current //包含许多hooks-api函数
根据上下文源码:
var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher,
根据上下文源码:
var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
mountState函数--返回hook.memoizedState和dispatch
function mountState(initialState) {
var hook = mountWorkInProgressHook();
if (typeof initialState === 'function') {
initialState = initialState();
}
hook.memoizedState = hook.baseState = initialState;
var queue = hook.queue = {
pending: null,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: initialState
};
var dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingFiber$1, queue);
return [hook.memoizedState, dispatch];
}
逐条分析:
1. mountWorkInProgressHook 见下文
2. function basicStateReducer(state, action) {
return typeof action === 'function' ? action(state) : action;
}
mountWorkInProgressHook函数--链式存储,fiber的memoizedState字段
function mountWorkInProgressHook() {
var hook = {
memoizedState: null,
baseState: null,
baseQueue: null,
queue: null,
next: null
};
if (workInProgressHook === null) {
currentlyRenderingFiber$1.memoizedState = workInProgressHook = hook;
} else {
workInProgressHook = workInProgressHook.next = hook;
}
return workInProgressHook;
}
根据上下文:
1. workInProgressHook 在render阶段任何时间节点是否计划更新,如果我们再做一次render渲染,这个不会重置,只有当我们完全完成对该组件的计算。我们知道这是一种优化我们是否需要在抛出后清除渲染阶段更新
2. currentlyRenderingFiber$1 hooks已链表形式存储在fiber的memoizedState字段,当前hooks列表属于当前fiber列表,workInProgressHook列表是将被添加到workInProgress fiber的新列表
dispatchAction函数--setData
function dispatchAction(fiber, queue, action) {
{
if (typeof arguments[3] === 'function') {
error("State updates from the useState() and useReducer() Hooks don't support the " + 'second callback argument. To execute a side effect after ' + 'rendering, declare it in the component body with useEffect().');
}
}
var eventTime = requestEventTime();
var lane = requestUpdateLane(fiber);
var update = {
lane: lane,
action: action,
eagerReducer: null,
eagerState: null,
next: null
};
var pending = queue.pending;
if (pending === null) {
update.next = update;
} else {
update.next = pending.next;
pending.next = update;
}
queue.pending = update;
var alternate = fiber.alternate;
if (fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1) {
didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true;
} else {
if (fiber.lanes === NoLanes && (alternate === null || alternate.lanes === NoLanes)) {
var lastRenderedReducer = queue.lastRenderedReducer;
if (lastRenderedReducer !== null) {
var prevDispatcher;
{
prevDispatcher = ReactCurrentDispatcher$1.current;
ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
}
try {
var currentState = queue.lastRenderedState;
var eagerState = lastRenderedReducer(currentState, action);
update.eagerReducer = lastRenderedReducer;
update.eagerState = eagerState;
if (objectIs(eagerState, currentState)) {
return;
}
} catch (error) {
} finally {
{
ReactCurrentDispatcher$1.current = prevDispatcher;
}
}
}
}
{
if ('undefined' !== typeof jest) {
warnIfNotScopedWithMatchingAct(fiber);
warnIfNotCurrentlyActingUpdatesInDev(fiber);
}
}
scheduleUpdateOnFiber(fiber, lane, eventTime);
}
}
requestEventTime函数--协调过程中所需要的时间
function requestEventTime() {
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
return now();
}
if (currentEventTime !== NoTimestamp) {
return currentEventTime;
}
currentEventTime = now();
return currentEventTime;
}
requestUpdateLane函数--更新优先级
function requestUpdateLane(fiber) {
var mode = fiber.mode;
if ((mode & BlockingMode) === NoMode) {
return SyncLane;
} else if ((mode & ConcurrentMode) === NoMode) {
return getCurrentPriorityLevel() === ImmediatePriority$1 ? SyncLane : SyncBatchedLane;
}
if (currentEventWipLanes === NoLanes) {
currentEventWipLanes = workInProgressRootIncludedLanes;
}
var isTransition = requestCurrentTransition() !== NoTransition;
if (isTransition) {
if (currentEventPendingLanes !== NoLanes) {
currentEventPendingLanes = mostRecentlyUpdatedRoot !== null ? mostRecentlyUpdatedRoot.pendingLanes : NoLanes;
}
return findTransitionLane(currentEventWipLanes, currentEventPendingLanes);
}
var schedulerPriority = getCurrentPriorityLevel();
var lane;
if (
(executionContext & DiscreteEventContext) !== NoContext && schedulerPriority === UserBlockingPriority$2) {
lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);
} else {
var schedulerLanePriority = schedulerPriorityToLanePriority(schedulerPriority);
lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);
}
return lane;
}
逐条分析:
1. lan模型代表执行优先级,SyncLane代表同步优先级为1
scheduleUpdateOnFiber函数
function scheduleUpdateOnFiber(fiber, lane, eventTime) {
checkForNestedUpdates();
warnAboutRenderPhaseUpdatesInDEV(fiber);
var root = markUpdateLaneFromFiberToRoot(fiber, lane);
if (root === null) {
warnAboutUpdateOnUnmountedFiberInDEV(fiber);
return null;
}
markRootUpdated(root, lane, eventTime);
if (root === workInProgressRoot) {
{
workInProgressRootUpdatedLanes = mergeLanes(workInProgressRootUpdatedLanes, lane);
}
if (workInProgressRootExitStatus === RootSuspendedWithDelay) {
markRootSuspended$1(root, workInProgressRootRenderLanes);
}
}
var priorityLevel = getCurrentPriorityLevel();
if (lane === SyncLane) {
if (
(executionContext & LegacyUnbatchedContext) !== NoContext &&
(executionContext & (RenderContext | CommitContext)) === NoContext) {
schedulePendingInteractions(root, lane);
performSyncWorkOnRoot(root);
} else {
ensureRootIsScheduled(root, eventTime);
schedulePendingInteractions(root, lane);
if (executionContext === NoContext) {
resetRenderTimer();
flushSyncCallbackQueue();
}
}
} else {
if ((executionContext & DiscreteEventContext) !== NoContext && (
priorityLevel === UserBlockingPriority$2 || priorityLevel === ImmediatePriority$1)) {
if (rootsWithPendingDiscreteUpdates === null) {
rootsWithPendingDiscreteUpdates = new Set([root]);
} else {
rootsWithPendingDiscreteUpdates.add(root);
}
}
ensureRootIsScheduled(root, eventTime);
schedulePendingInteractions(root, lane);
}
mostRecentlyUpdatedRoot = root;
}
markUpdateLaneFromFiberToRoot函数--根节点(root)调度任务
使用这个函数为根节点(root)调度任务,每个根节点只有一个任务;如果一个任务已经被调度,我们将检查以确保现有任务的优先级与根节点所工作的下一级别的优先级相同。这个函数在每次更新时调用,并且在退出任务之前调用。
function markUpdateLaneFromFiberToRoot(sourceFiber, lane) {
sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);
var alternate = sourceFiber.alternate;
if (alternate !== null) {
alternate.lanes = mergeLanes(alternate.lanes, lane);
}
{
if (alternate === null && (sourceFiber.flags & (Placement | Hydrating)) !== NoFlags) {
warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);
}
}
var node = sourceFiber;
var parent = sourceFiber.return;
while (parent !== null) {
parent.childLanes = mergeLanes(parent.childLanes, lane);
alternate = parent.alternate;
if (alternate !== null) {
alternate.childLanes = mergeLanes(alternate.childLanes, lane);
} else {
{
if ((parent.flags & (Placement | Hydrating)) !== NoFlags) {
warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);
}
}
}
node = parent;
parent = parent.return;
}
if (node.tag === HostRoot) {
var root = node.stateNode;
return root;
} else {
return null;
}
}
markRootUpdated函数--标记根节点更新相关属性
function markRootUpdated(root, updateLane, eventTime) {
root.pendingLanes |= updateLane
现在,我们使用与旧的过期时间模型相同的启发式方法:重试一些lane在相同或者较低优先级,
但是不要尝试更新更高优先级的,不包含低优先级的更新。这工作得很好当考虑跨越不同优先级的更新时,但不是对于相同优先级的更新来说足够了,因为我们想要处理的这些更新是并行的。解除所有同等或更低优先级的更新。
var higherPriorityLanes = updateLane - 1
root.suspendedLanes &= higherPriorityLanes
root.pingedLanes &= higherPriorityLanes
var eventTimes = root.eventTimes
var index = laneToIndex(updateLane)
最近的事件,我们假设时间是单调递增的。
eventTimes[index] = eventTime
}
performSyncWorkOnRoot
function performSyncWorkOnRoot(root) {
if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {
{
throw Error( "Should not already be working." );
}
}
flushPassiveEffects();
var lanes;
var exitStatus;
if (root === workInProgressRoot && includesSomeLane(root.expiredLanes, workInProgressRootRenderLanes)) {
lanes = workInProgressRootRenderLanes;
exitStatus = renderRootSync(root, lanes);
if (includesSomeLane(workInProgressRootIncludedLanes, workInProgressRootUpdatedLanes)) {
lanes = getNextLanes(root, lanes);
exitStatus = renderRootSync(root, lanes);
}
} else {
lanes = getNextLanes(root, NoLanes);
exitStatus = renderRootSync(root, lanes);
}
if (root.tag !== LegacyRoot && exitStatus === RootErrored) {
executionContext |= RetryAfterError;
if (root.hydrate) {
root.hydrate = false;
clearContainer(root.containerInfo);
}
lanes = getLanesToRetrySynchronouslyOnError(root);
if (lanes !== NoLanes) {
exitStatus = renderRootSync(root, lanes);
}
}
if (exitStatus === RootFatalErrored) {
var fatalError = workInProgressRootFatalError;
prepareFreshStack(root, NoLanes);
markRootSuspended$1(root, lanes);
ensureRootIsScheduled(root, now());
throw fatalError;
}
var finishedWork = root.current.alternate;
root.finishedWork = finishedWork;
root.finishedLanes = lanes;
commitRoot(root);
ensureRootIsScheduled(root, now());
return null;
}
ensureRootIsScheduled
function ensureRootIsScheduled(root, currentTime) {
var existingCallbackNode = root.callbackNode;
markStarvedLanesAsExpired(root, currentTime);
var nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes);
var newCallbackPriority = returnNextLanesPriority();
if (nextLanes === NoLanes) {
if (existingCallbackNode !== null) {
cancelCallback(existingCallbackNode);
root.callbackNode = null;
root.callbackPriority = NoLanePriority;
}
return;
}
if (existingCallbackNode !== null) {
var existingCallbackPriority = root.callbackPriority;
if (existingCallbackPriority === newCallbackPriority) {
return;
}
cancelCallback(existingCallbackNode);
}
var newCallbackNode;
if (newCallbackPriority === SyncLanePriority) {
newCallbackNode = scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root));
} else if (newCallbackPriority === SyncBatchedLanePriority) {
newCallbackNode = scheduleCallback(ImmediatePriority$1, performSyncWorkOnRoot.bind(null, root));
} else {
var schedulerPriorityLevel = lanePriorityToSchedulerPriority(newCallbackPriority);
newCallbackNode = scheduleCallback(schedulerPriorityLevel, performConcurrentWorkOnRoot.bind(null, root));
}
root.callbackPriority = newCallbackPriority;
root.callbackNode = newCallbackNode;
}