diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.new.js b/packages/react-reconciler/src/ReactFiberBeginWork.new.js index c3bf502ac61..ab0705fa7a9 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.new.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.new.js @@ -981,6 +981,15 @@ function updateTracingMarkerComponent( }; workInProgress.stateNode = markerInstance; } + } else { + if (__DEV__) { + if (current.memoizedProps.name !== workInProgress.pendingProps.name) { + console.error( + 'Changing the name of a tracing marker after mount is not supported. ' + + 'To remount the tracing marker, pass it a new key.', + ); + } + } } const instance: TracingMarkerInstance | null = workInProgress.stateNode; diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.old.js b/packages/react-reconciler/src/ReactFiberBeginWork.old.js index f9a53f66100..48a932df780 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.old.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.old.js @@ -981,6 +981,15 @@ function updateTracingMarkerComponent( }; workInProgress.stateNode = markerInstance; } + } else { + if (__DEV__) { + if (current.memoizedProps.name !== workInProgress.pendingProps.name) { + console.error( + 'Changing the name of a tracing marker after mount is not supported. ' + + 'To remount the tracing marker, pass it a new key.', + ); + } + } } const instance: TracingMarkerInstance | null = workInProgress.stateNode; diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index 6f46abdcddc..097628db06d 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -3044,14 +3044,16 @@ function commitPassiveMountOnFiber( instance.pendingSuspenseBoundaries === null || instance.pendingSuspenseBoundaries.size === 0 ) { - instance.transitions.forEach(transition => { - addMarkerCompleteCallbackToPendingTransition({ - transition, - name: finishedWork.memoizedProps.name, + if (instance.transitions !== null) { + instance.transitions.forEach(transition => { + addMarkerCompleteCallbackToPendingTransition({ + transition, + name: finishedWork.memoizedProps.name, + }); }); - }); - instance.transitions = null; - instance.pendingSuspenseBoundaries = null; + instance.transitions = null; + instance.pendingSuspenseBoundaries = null; + } } } break; diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.old.js b/packages/react-reconciler/src/ReactFiberCommitWork.old.js index bc7fc9ae36a..252200fd5fb 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.old.js @@ -3044,14 +3044,16 @@ function commitPassiveMountOnFiber( instance.pendingSuspenseBoundaries === null || instance.pendingSuspenseBoundaries.size === 0 ) { - instance.transitions.forEach(transition => { - addMarkerCompleteCallbackToPendingTransition({ - transition, - name: finishedWork.memoizedProps.name, + if (instance.transitions !== null) { + instance.transitions.forEach(transition => { + addMarkerCompleteCallbackToPendingTransition({ + transition, + name: finishedWork.memoizedProps.name, + }); }); - }); - instance.transitions = null; - instance.pendingSuspenseBoundaries = null; + instance.transitions = null; + instance.pendingSuspenseBoundaries = null; + } } } break; diff --git a/packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js b/packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js index c590741094b..29d9cc8f492 100644 --- a/packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js +++ b/packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js @@ -1059,6 +1059,86 @@ describe('ReactInteractionTracing', () => { }); }); + // @gate enableTransitionTracing + it('warns when marker name changes', async () => { + const transitionCallbacks = { + onTransitionStart: (name, startTime) => { + Scheduler.unstable_yieldValue( + `onTransitionStart(${name}, ${startTime})`, + ); + }, + onTransitionComplete: (name, startTime, endTime) => { + Scheduler.unstable_yieldValue( + `onTransitionComplete(${name}, ${startTime}, ${endTime})`, + ); + }, + onMarkerComplete: (transitioName, markerName, startTime, endTime) => { + Scheduler.unstable_yieldValue( + `onMarkerComplete(${transitioName}, ${markerName}, ${startTime}, ${endTime})`, + ); + }, + }; + function App({markerName, markerKey}) { + return ( + + + + ); + } + + const root = ReactNoop.createRoot({transitionCallbacks}); + await act(async () => { + startTransition( + () => root.render(), + { + name: 'transition one', + }, + ); + ReactNoop.expire(1000); + await advanceTimers(1000); + expect(Scheduler).toFlushAndYield([ + 'one', + 'onTransitionStart(transition one, 0)', + 'onMarkerComplete(transition one, one, 0, 1000)', + 'onTransitionComplete(transition one, 0, 1000)', + ]); + startTransition( + () => root.render(), + { + name: 'transition two', + }, + ); + ReactNoop.expire(1000); + await advanceTimers(1000); + expect(() => { + // onMarkerComplete shouldn't be called for transitions with + // new keys + expect(Scheduler).toFlushAndYield([ + 'two', + 'onTransitionStart(transition two, 1000)', + 'onTransitionComplete(transition two, 1000, 2000)', + ]); + }).toErrorDev( + 'Changing the name of a tracing marker after mount is not supported.', + ); + startTransition( + () => root.render(), + { + name: 'transition three', + }, + ); + ReactNoop.expire(1000); + await advanceTimers(1000); + // This should not warn and onMarkerComplete should be called + expect(Scheduler).toFlushAndYield([ + 'three', + 'onTransitionStart(transition three, 2000)', + 'onMarkerComplete(transition three, three, 2000, 3000)', + 'onTransitionComplete(transition three, 2000, 3000)', + ]); + }); + }); + // @gate enableTransitionTracing it.skip('marker interaction cancelled when name changes', async () => { const transitionCallbacks = {