From 5f4bc2294d3d3451d04c9bd8cf4bcf8f37695050 Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 6 Jul 2022 13:06:51 -0400 Subject: [PATCH] marker progress --- .../src/ReactFiberCommitWork.new.js | 23 ++- .../ReactFiberTracingMarkerComponent.new.js | 15 ++ .../src/ReactFiberWorkLoop.new.js | 27 +++ .../__tests__/ReactTransitionTracing-test.js | 163 +++++++++++++++++- 4 files changed, 216 insertions(+), 12 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index c8bc83d25a312..e535b66a43b28 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -144,6 +144,7 @@ import { addTransitionStartCallbackToPendingTransition, addTransitionProgressCallbackToPendingTransition, addTransitionCompleteCallbackToPendingTransition, + addMarkerProgressCallbackToPendingTransition, addMarkerCompleteCallbackToPendingTransition, setIsRunningInsertionEffect, } from './ReactFiberWorkLoop.new'; @@ -3039,17 +3040,27 @@ function commitPassiveMountOnFiber( // Get the transitions that were initiatized during the render // and add a start transition callback for each of them const instance = finishedWork.stateNode; - if (instance.transitions !== null) { - if ( + if (instance.transitions !== null && instance.hasUpdate) { + const transitionsComplete = instance.pendingSuspenseBoundaries === null || - instance.pendingSuspenseBoundaries.size === 0 - ) { - instance.transitions.forEach(transition => { + instance.pendingSuspenseBoundaries.size === 0; + + instance.transitions.forEach(transition => { + addMarkerProgressCallbackToPendingTransition({ + transition, + name: finishedWork.memoizedProps.name, + pending: instance.pendingSuspenseBoundaries, + }); + + if (transitionsComplete) { addMarkerCompleteCallbackToPendingTransition({ transition, name: finishedWork.memoizedProps.name, }); - }); + } + }); + instance.hasUpdate = false; + if (transitionsComplete) { instance.transitions = null; instance.pendingSuspenseBoundaries = null; } diff --git a/packages/react-reconciler/src/ReactFiberTracingMarkerComponent.new.js b/packages/react-reconciler/src/ReactFiberTracingMarkerComponent.new.js index 8c0b53c295759..8c8991537b920 100644 --- a/packages/react-reconciler/src/ReactFiberTracingMarkerComponent.new.js +++ b/packages/react-reconciler/src/ReactFiberTracingMarkerComponent.new.js @@ -31,6 +31,7 @@ export type PendingTransitionCallbacks = { transitionStart: Array | null, transitionProgress: Array | null, transitionComplete: Array | null, + markerProgress: Array | null, markerComplete: Array | null, }; @@ -73,6 +74,20 @@ export function processTransitionCallbacks( }); } + const markerProgress = pendingTransitions.markerProgress; + const onMarkerProgress = callbacks.onMarkerProgress; + if (onMarkerProgress != null && markerProgress !== null) { + markerProgress.forEach(marker => { + onMarkerProgress( + marker.transition.name, + marker.name, + marker.transition.startTime, + endTime, + Array.from(marker.pending.values()), + ); + }); + } + const markerComplete = pendingTransitions.markerComplete; if (markerComplete !== null) { markerComplete.forEach(marker => { diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js index f17f5e0bc9f51..3e65e4e6bf03f 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js @@ -17,6 +17,7 @@ import type {EventPriority} from './ReactEventPriorities.new'; import type { PendingTransitionCallbacks, MarkerTransition, + MarkerTransitionProgress, Transition, TransitionProgress, } from './ReactFiberTracingMarkerComponent.new'; @@ -342,6 +343,7 @@ export function addTransitionStartCallbackToPendingTransition( transitionStart: [], transitionProgress: null, transitionComplete: null, + markerProgress: null, markerComplete: null, }; } @@ -354,6 +356,28 @@ export function addTransitionStartCallbackToPendingTransition( } } +export function addMarkerProgressCallbackToPendingTransition( + transition: MarkerTransitionProgress, +) { + if (enableTransitionTracing) { + if (currentPendingTransitionCallbacks === null) { + currentPendingTransitionCallbacks = { + transitionStart: null, + transitionProgress: null, + transitionComplete: null, + markerProgress: [], + markerComplete: null, + }; + } + + if (currentPendingTransitionCallbacks.markerProgress === null) { + currentPendingTransitionCallbacks.markerProgress = []; + } + + currentPendingTransitionCallbacks.markerProgress.push(transition); + } +} + export function addMarkerCompleteCallbackToPendingTransition( transition: MarkerTransition, ) { @@ -363,6 +387,7 @@ export function addMarkerCompleteCallbackToPendingTransition( transitionStart: null, transitionProgress: null, transitionComplete: null, + markerProgress: null, markerComplete: [], }; } @@ -384,6 +409,7 @@ export function addTransitionProgressCallbackToPendingTransition( transitionStart: null, transitionProgress: [], transitionComplete: null, + markerProgress: null, markerComplete: null, }; } @@ -405,6 +431,7 @@ export function addTransitionCompleteCallbackToPendingTransition( transitionStart: null, transitionProgress: null, transitionComplete: [], + markerProgress: null, markerComplete: null, }; } diff --git a/packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js b/packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js index e94aee6a25b41..7ed52ec2b5be5 100644 --- a/packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js +++ b/packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js @@ -861,18 +861,116 @@ describe('ReactInteractionTracing', () => { }); // @gate enableTransitionTracing - it('should correctly trace interactions for tracing markers complete', async () => { + it('should correctly trace basic interaction with tracing markers', async () => { const transitionCallbacks = { onTransitionStart: (name, startTime) => { Scheduler.unstable_yieldValue( `onTransitionStart(${name}, ${startTime})`, ); }, + onTransitionProgress: (name, startTime, endTime, pending) => { + const suspenseNames = pending.map(p => p.name || '').join(', '); + Scheduler.unstable_yieldValue( + `onTransitionProgress(${name}, ${startTime}, ${endTime}, [${suspenseNames}])`, + ); + }, onTransitionComplete: (name, startTime, endTime) => { Scheduler.unstable_yieldValue( `onTransitionComplete(${name}, ${startTime}, ${endTime})`, ); }, + onMarkerProgress: ( + transitioName, + markerName, + startTime, + currentTime, + pending, + ) => { + const suspenseNames = pending.map(p => p.name || '').join(', '); + Scheduler.unstable_yieldValue( + `onMarkerProgress(${transitioName}, ${markerName}, ${startTime}, ${currentTime}, [${suspenseNames}])`, + ); + }, + onMarkerComplete: (transitioName, markerName, startTime, endTime) => { + Scheduler.unstable_yieldValue( + `onMarkerComplete(${transitioName}, ${markerName}, ${startTime}, ${endTime})`, + ); + }, + }; + + let navigateToPageTwo; + function App() { + const [navigate, setNavigate] = useState(false); + navigateToPageTwo = () => { + setNavigate(true); + }; + + return ( +
+ {navigate ? ( + + + + ) : ( + + + + )} +
+ ); + } + + const root = ReactNoop.createRoot({transitionCallbacks}); + await act(async () => { + root.render(); + ReactNoop.expire(1000); + await advanceTimers(1000); + + expect(Scheduler).toFlushAndYield(['Page One']); + + await act(async () => { + startTransition(() => navigateToPageTwo(), {name: 'page transition'}); + + ReactNoop.expire(1000); + await advanceTimers(1000); + + expect(Scheduler).toFlushAndYield([ + 'Page Two', + 'onTransitionStart(page transition, 1000)', + 'onMarkerProgress(page transition, marker two, 1000, 2000, [])', + 'onMarkerComplete(page transition, marker two, 1000, 2000)', + 'onTransitionProgress(page transition, 1000, 2000, [])', + 'onTransitionComplete(page transition, 1000, 2000)', + ]); + }); + }); + }); + + // @gate enableTransitionTracing + it('should correctly trace interactions for tracing markers', async () => { + const transitionCallbacks = { + onTransitionStart: (name, startTime) => { + Scheduler.unstable_yieldValue( + `onTransitionStart(${name}, ${startTime})`, + ); + }, + onTransitionComplete: (name, startTime, endTime) => { + Scheduler.unstable_yieldValue( + `onTransitionComplete(${name}, ${startTime}, ${endTime})`, + ); + }, + onMarkerProgress: ( + transitioName, + markerName, + startTime, + currentTime, + pending, + ) => { + const suspenseNames = pending.map(p => p.name || '').join(', '); + Scheduler.unstable_yieldValue( + `onMarkerProgress(${transitioName}, ${markerName}, ${startTime}, ${currentTime}, [${suspenseNames}])`, + ); + }, onMarkerComplete: (transitioName, markerName, startTime, endTime) => { Scheduler.unstable_yieldValue( `onMarkerComplete(${transitioName}, ${markerName}, ${startTime}, ${endTime})`, @@ -891,13 +989,13 @@ describe('ReactInteractionTracing', () => { {navigate ? ( } - name="suspense page"> + unstable_name="suspense page"> } - name="marker suspense"> + unstable_name="marker suspense"> @@ -940,6 +1038,8 @@ describe('ReactInteractionTracing', () => { 'Page Two', 'Suspend [Marker Text]', 'Loading...', + 'onMarkerProgress(page transition, sync marker, 1000, 3000, [])', + 'onMarkerProgress(page transition, async marker, 1000, 3000, [marker suspense])', 'onMarkerComplete(page transition, sync marker, 1000, 3000)', ]); @@ -949,6 +1049,7 @@ describe('ReactInteractionTracing', () => { expect(Scheduler).toFlushAndYield([ 'Marker Text', + 'onMarkerProgress(page transition, async marker, 1000, 4000, [])', 'onMarkerComplete(page transition, async marker, 1000, 4000)', 'onTransitionComplete(page transition, 1000, 4000)', ]); @@ -968,6 +1069,18 @@ describe('ReactInteractionTracing', () => { `onTransitionComplete(${name}, ${startTime}, ${endTime})`, ); }, + onMarkerProgress: ( + transitioName, + markerName, + startTime, + currentTime, + pending, + ) => { + const suspenseNames = pending.map(p => p.name || '').join(', '); + Scheduler.unstable_yieldValue( + `onMarkerProgress(${transitioName}, ${markerName}, ${startTime}, ${currentTime}, [${suspenseNames}])`, + ); + }, onMarkerComplete: (transitioName, markerName, startTime, endTime) => { Scheduler.unstable_yieldValue( `onMarkerComplete(${transitioName}, ${markerName}, ${startTime}, ${endTime})`, @@ -986,14 +1099,20 @@ describe('ReactInteractionTracing', () => {
{navigate ? ( - }> + } + unstable_name="outer"> - }> + } + unstable_name="inner one"> - }> + } + unstable_name="inner two"> @@ -1030,6 +1149,7 @@ describe('ReactInteractionTracing', () => { 'Inner Two...', 'Outer...', 'onTransitionStart(page transition, 1000)', + 'onMarkerProgress(page transition, outer marker, 1000, 2000, [outer])', ]); ReactNoop.expire(1000); @@ -1045,6 +1165,8 @@ describe('ReactInteractionTracing', () => { 'Suspend [Inner Text One]', 'Inner One...', 'Inner Text Two', + 'onMarkerProgress(page transition, marker two, 1000, 4000, [])', + 'onMarkerProgress(page transition, outer marker, 1000, 4000, [inner one])', 'onMarkerComplete(page transition, marker two, 1000, 4000)', ]); @@ -1053,6 +1175,8 @@ describe('ReactInteractionTracing', () => { await resolveText('Inner Text One'); expect(Scheduler).toFlushAndYield([ 'Inner Text One', + 'onMarkerProgress(page transition, marker one, 1000, 5000, [])', + 'onMarkerProgress(page transition, outer marker, 1000, 5000, [])', 'onMarkerComplete(page transition, marker one, 1000, 5000)', 'onMarkerComplete(page transition, outer marker, 1000, 5000)', 'onTransitionComplete(page transition, 1000, 5000)', @@ -1073,6 +1197,18 @@ describe('ReactInteractionTracing', () => { `onTransitionComplete(${name}, ${startTime}, ${endTime})`, ); }, + onMarkerProgress: ( + transitioName, + markerName, + startTime, + currentTime, + pending, + ) => { + const suspenseNames = pending.map(p => p.name || '').join(', '); + Scheduler.unstable_yieldValue( + `onMarkerProgress(${transitioName}, ${markerName}, ${startTime}, ${currentTime}, [${suspenseNames}])`, + ); + }, onMarkerComplete: (transitioName, markerName, startTime, endTime) => { Scheduler.unstable_yieldValue( `onMarkerComplete(${transitioName}, ${markerName}, ${startTime}, ${endTime})`, @@ -1119,6 +1255,7 @@ describe('ReactInteractionTracing', () => { 'Suspend [Page Two]', 'Loading...', 'onTransitionStart(page transition, 1000)', + 'onMarkerProgress(page transition, old marker, 1000, 1000, [])', ]); ReactNoop.expire(1000); @@ -1150,6 +1287,18 @@ describe('ReactInteractionTracing', () => { `onTransitionComplete(${name}, ${startTime}, ${endTime})`, ); }, + onMarkerProgress: ( + transitioName, + markerName, + startTime, + currentTime, + pending, + ) => { + const suspenseNames = pending.map(p => p.name || '').join(', '); + Scheduler.unstable_yieldValue( + `onMarkerProgress(${transitioName}, ${markerName}, ${startTime}, ${currentTime}, [${suspenseNames}])`, + ); + }, onMarkerComplete: (transitioName, markerName, startTime, endTime) => { Scheduler.unstable_yieldValue( `onMarkerComplete(${transitioName}, ${markerName}, ${startTime}, ${endTime})`, @@ -1199,6 +1348,7 @@ describe('ReactInteractionTracing', () => { 'Suspend [Page Two]', 'Loading...', 'onTransitionStart(page transition, 1000)', + 'onMarkerProgress(page transition, old marker, 1000, 2000, [])', ]); startTransition(() => setMarkerNameFn(), {name: 'marker transition'}); @@ -1209,6 +1359,7 @@ describe('ReactInteractionTracing', () => { 'Suspend [Page Two]', 'Loading...', 'onTransitionStart(marker transition, 2000)', + 'onMarkerProgress(marker transition, new marker, 2000, 3000, [])', 'onMarkerComplete(marker transition, new marker, 2000, 3000)', 'onTransitionComplete(marker transition, 2000, 3000)', ]);