跳到主要内容

react 开始过渡

一、作用

二、开始过渡

备注
export function startTransition(
scope: () => void,
options?: StartTransitionOptions,
): void {
const prevTransition = ReactSharedInternals.T;
const currentTransition: Transition = {} as any;
if (enableViewTransition) {
currentTransition.types =
prevTransition !== null
? // If we're a nested transition, we should use the same set as the parent
// since we're conceptually always joined into the same entangled transition.
// In practice, this only matters if we add transition types in the inner
// without setting state. In that case, the inner transition can finish
// without waiting for the outer.
//
// 如果我们是嵌套的过渡,我们应该使用与父过渡相同的集合。因为从概念上讲,我们总是加入同一个纠缠
// 的过渡。实际上,这只有在我们在内部添加过渡类型而没有设置状态时才重要。在这种情况下,内部过渡
// 可以在不等待外部过渡的情况下完成。
prevTransition.types
: null;
}
if (enableGestureTransition) {
currentTransition.gesture = null;
}
if (enableTransitionTracing) {
currentTransition.name =
options !== undefined && options.name !== undefined ? options.name : null;
// 待办:这里应该读取时间戳。
currentTransition.startTime = -1; // TODO: This should read the timestamp.
}
if (__DEV__) {
currentTransition._updatedFibers = new Set();
}
ReactSharedInternals.T = currentTransition;

try {
const returnValue = scope();
const onStartTransitionFinish = ReactSharedInternals.S;
if (onStartTransitionFinish !== null) {
onStartTransitionFinish(currentTransition, returnValue);
}
if (
typeof returnValue === 'object' &&
returnValue !== null &&
typeof returnValue.then === 'function'
) {
if (__DEV__) {
// Keep track of the number of async transitions still running so we can warn.
// 跟踪仍在运行的异步过渡数量,以便我们可以发出警告。
ReactSharedInternals.asyncTransitions++;
returnValue.then(releaseAsyncTransition, releaseAsyncTransition);
}
returnValue.then(noop, reportGlobalError);
}
} catch (error) {
reportGlobalError(error);
} finally {
warnAboutTransitionSubscriptions(prevTransition, currentTransition);
if (prevTransition !== null && currentTransition.types !== null) {
// If we created a new types set in the inner transition, we transfer it to the parent
// since they should share the same set. They're conceptually entangled.
//
// 如果我们在内部过渡中创建了一个新的类型集合,我们会将其传递给父级。因为它们应该共享同一个集合,本质上
// 是相互关联的。
if (__DEV__) {
if (
prevTransition.types !== null &&
prevTransition.types !== currentTransition.types
) {
// Just assert that assumption holds that we're not overriding anything.
// 只是断言这个假设成立,即我们没有覆盖任何东西。
console.error(
'We expected inner Transitions to have transferred the outer types set and ' +
'that you cannot add to the outer Transition while inside the inner.' +
'This is a bug in React.',
);
}
}
prevTransition.types = currentTransition.types;
}
ReactSharedInternals.T = prevTransition;
}
}

三、开始手势过渡

备注
export function startGestureTransition(
provider: GestureProvider,
scope: () => void,
options?: GestureOptions & StartTransitionOptions,
): () => void {
if (!enableGestureTransition) {
throw new Error(
'startGestureTransition should not be exported when the enableGestureTransition flag is off.',
);
}
if (provider == null) {
// We enforce this at runtime even though the type also enforces it since we
// use null as a signal internally so it would lead it to be treated as a
// regular transition otherwise.
//
// 即使类型本身也会强制这一点,我们在运行时仍然会强制执行它,因为我们内部使用 null 作为信号,
// 否则它会被当作普通的转换处理。
throw new Error(
'A Timeline is required as the first argument to startGestureTransition.',
);
}
const prevTransition = ReactSharedInternals.T;
const currentTransition: Transition = {} as any;
if (enableViewTransition) {
currentTransition.types = null;
}
if (enableGestureTransition) {
currentTransition.gesture = provider;
}
if (enableTransitionTracing) {
currentTransition.name =
options !== undefined && options.name !== undefined ? options.name : null;
// 待办:这里应该读取时间戳。
currentTransition.startTime = -1; // TODO: This should read the timestamp.
}
if (__DEV__) {
currentTransition._updatedFibers = new Set();
}
ReactSharedInternals.T = currentTransition;

try {
const returnValue = scope();
if (__DEV__) {
if (
typeof returnValue === 'object' &&
returnValue !== null &&
typeof returnValue.then === 'function'
) {
console.error(
'Cannot use an async function in startGestureTransition. It must be able to start immediately.',
);
}
}
const onStartGestureTransitionFinish = ReactSharedInternals.G;
if (onStartGestureTransitionFinish !== null) {
return onStartGestureTransitionFinish(
currentTransition,
provider,
options,
);
}
} catch (error) {
reportGlobalError(error);
} finally {
ReactSharedInternals.T = prevTransition;
}
return noop;
}

四、工具

1. 异步释放过渡

备注
function releaseAsyncTransition() {
if (__DEV__) {
ReactSharedInternals.asyncTransitions--;
}
}

2. 警告过渡订阅

function warnAboutTransitionSubscriptions(
prevTransition: Transition | null,
currentTransition: Transition,
) {
if (__DEV__) {
if (prevTransition === null && currentTransition._updatedFibers) {
const updatedFibersCount = currentTransition._updatedFibers.size;
currentTransition._updatedFibers.clear();
if (updatedFibersCount > 10) {
console.warn(
'Detected a large number of updates inside startTransition. ' +
'If this is due to a subscription please re-write it to use React provided hooks. ' +
'Otherwise concurrent mode guarantees are off the table.',
);
}
}
}
}