From 921c4f82fc348151e3763e9dad0d147eff3bcf73 Mon Sep 17 00:00:00 2001 From: Luna Ruan Date: Tue, 30 Jul 2019 14:16:30 -0700 Subject: [PATCH 1/5] fix react suspense priority location --- .../src/ReactFiberWorkLoop.js | 67 ++++++++++--------- .../__tests__/ReactSuspense-test.internal.js | 10 --- ...tSuspenseWithNoopRenderer-test.internal.js | 64 +++++++++--------- .../__tests__/ReactProfiler-test.internal.js | 5 +- 4 files changed, 72 insertions(+), 74 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index d4d4872450f..53a51eba0d3 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -983,8 +983,6 @@ function renderRoot( // Set this to null to indicate there's no in-progress render. workInProgressRoot = null; - flushSuspensePriorityWarningInDEV(); - switch (workInProgressRootExitStatus) { case RootIncomplete: { invariant(false, 'Should have a work-in-progress.'); @@ -1015,6 +1013,8 @@ function renderRoot( return commitRoot.bind(null, root); } case RootSuspended: { + flushSuspensePriorityWarningInDEV(); + // We have an acceptable loading state. We need to figure out if we should // immediately commit it or wait a bit. @@ -1060,6 +1060,8 @@ function renderRoot( return commitRoot.bind(null, root); } case RootSuspendedWithDelay: { + flushSuspensePriorityWarningInDEV(); + if (!isSync) { // We're suspended in a state that should be avoided. We'll try to avoid committing // it for as long as the timeouts let us. @@ -2640,39 +2642,44 @@ function flushSuspensePriorityWarningInDEV() { componentsThatTriggeredHighPriSuspend = null; const componentNamesString = componentNames.sort().join(', '); - let componentThatTriggeredSuspenseError = ''; if (componentsThatTriggeredSuspendNames.length > 0) { - componentThatTriggeredSuspenseError = + warningWithoutStack( + false, 'The following components triggered a user-blocking update:' + - '\n\n' + - ' ' + - componentsThatTriggeredSuspendNames.sort().join(', ') + - '\n\n' + - 'that was then suspended by:' + - '\n\n' + - ' ' + - componentNamesString; + '\n\n' + + ' %s' + + '\n\n' + + 'that was then suspended by:' + + '\n\n' + + ' %s' + + '\n\n' + + 'The fix is to split the update into multiple parts: a user-blocking ' + + 'update to provide immediate feedback, and another update that ' + + 'triggers the bulk of the changes.' + + '\n\n' + + 'Refer to the documentation for useSuspenseTransition to learn how ' + + 'to implement this pattern.', + // TODO: Add link to React docs with more information, once it exists + componentsThatTriggeredSuspendNames.sort().join(', '), + componentNamesString, + ); } else { - componentThatTriggeredSuspenseError = + warningWithoutStack( + false, 'A user-blocking update was suspended by:' + - '\n\n' + - ' ' + - componentNamesString; + '\n\n' + + ' %s' + + '\n\n' + + 'The fix is to split the update into multiple parts: a user-blocking ' + + 'update to provide immediate feedback, and another update that ' + + 'triggers the bulk of the changes.' + + '\n\n' + + 'Refer to the documentation for useSuspenseTransition to learn how ' + + 'to implement this pattern.', + // TODO: Add link to React docs with more information, once it exists + componentNamesString, + ); } - - warningWithoutStack( - false, - '%s' + - '\n\n' + - 'The fix is to split the update into multiple parts: a user-blocking ' + - 'update to provide immediate feedback, and another update that ' + - 'triggers the bulk of the changes.' + - '\n\n' + - 'Refer to the documentation for useSuspenseTransition to learn how ' + - 'to implement this pattern.', - // TODO: Add link to React docs with more information, once it exists - componentThatTriggeredSuspenseError, - ); } } } diff --git a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js index 5050c2936ff..d7e3561ac95 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js @@ -341,16 +341,6 @@ describe('ReactSuspense', () => { 'AsyncText suspended while rendering, but no fallback UI was specified.', ); expect(Scheduler).toHaveYielded(['Suspend! [Hi]', 'Suspend! [Hi]']); - if (__DEV__) { - expect(console.error).toHaveBeenCalledTimes(2); - expect(console.error.calls.argsFor(0)[0]).toContain( - 'Warning: %s\n\nThe fix is to split the update', - ); - expect(console.error.calls.argsFor(0)[1]).toContain( - 'A user-blocking update was suspended by:', - ); - expect(console.error.calls.argsFor(0)[1]).toContain('AsyncText'); - } }); describe('outside concurrent mode', () => { diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js index 8c9773009b2..5aa744e09e8 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js @@ -488,7 +488,6 @@ describe('ReactSuspenseWithNoopRenderer', () => { }); it('tries rendering a lower priority pending update even if a higher priority one suspends', async () => { - spyOnDev(console, 'error'); function App(props) { if (props.hide) { return ; @@ -516,16 +515,6 @@ describe('ReactSuspenseWithNoopRenderer', () => { '(empty)', ]); expect(ReactNoop.getChildren()).toEqual([span('(empty)')]); - if (__DEV__) { - expect(console.error).toHaveBeenCalledTimes(1); - expect(console.error.calls.argsFor(0)[0]).toContain( - 'Warning: %s\n\nThe fix is to split the update', - ); - expect(console.error.calls.argsFor(0)[1]).toContain( - 'A user-blocking update was suspended by:', - ); - expect(console.error.calls.argsFor(0)[1]).toContain('AsyncText'); - } }); it('forces an expiration after an update times out', async () => { @@ -674,10 +663,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { if (__DEV__) { expect(console.error).toHaveBeenCalledTimes(1); expect(console.error.calls.argsFor(0)[0]).toContain( - 'Warning: %s\n\nThe fix is to split the update', - ); - expect(console.error.calls.argsFor(0)[1]).toContain( - 'A user-blocking update was suspended by:', + 'Warning: A user-blocking update was suspended by:', ); expect(console.error.calls.argsFor(0)[1]).toContain('AsyncText'); } @@ -710,10 +696,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { if (__DEV__) { expect(console.error).toHaveBeenCalledTimes(1); expect(console.error.calls.argsFor(0)[0]).toContain( - 'Warning: %s\n\nThe fix is to split the update', - ); - expect(console.error.calls.argsFor(0)[1]).toContain( - 'A user-blocking update was suspended by:', + 'Warning: A user-blocking update was suspended by:', ); expect(console.error.calls.argsFor(0)[1]).toContain('AsyncText'); } @@ -794,21 +777,10 @@ describe('ReactSuspenseWithNoopRenderer', () => { }); it('throws a helpful error when an update is suspends without a placeholder', () => { - spyOnDev(console, 'error'); ReactNoop.render(); expect(Scheduler).toFlushAndThrow( 'AsyncText suspended while rendering, but no fallback UI was specified.', ); - if (__DEV__) { - expect(console.error).toHaveBeenCalledTimes(2); - expect(console.error.calls.argsFor(0)[0]).toContain( - 'Warning: %s\n\nThe fix is to split the update', - ); - expect(console.error.calls.argsFor(0)[1]).toContain( - 'A user-blocking update was suspended by:', - ); - expect(console.error.calls.argsFor(0)[1]).toContain('AsyncText'); - } }); it('a Suspense component correctly handles more than one suspended child', async () => { @@ -1737,6 +1709,38 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); }); + it('', async () => { + let showB; + class App extends React.Component { + state = {showB: false}; + + render() { + showB = () => this.setState({showB: true}); + return ( + + {} + {this.state.showB && } + + ); + } + } + + await ReactNoop.act(async () => { + ReactNoop.render(); + }); + + expect(Scheduler).toHaveYielded(['Suspend! [A]']); + + ReactNoop.act(() => { + Scheduler.unstable_runWithPriority( + Scheduler.unstable_UserBlockingPriority, + () => showB(), + ); + }); + + expect(Scheduler).toHaveYielded(['Suspend! [A]', 'Suspend! [B]']); + }); + it('warns when suspending inside discrete update', async () => { function A() { Scheduler.unstable_yieldValue('A'); diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js index c1a99452946..2237249cd7f 100644 --- a/packages/react/src/__tests__/ReactProfiler-test.internal.js +++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js @@ -2733,10 +2733,7 @@ describe('Profiler', () => { if (__DEV__) { expect(console.error).toHaveBeenCalledTimes(1); expect(console.error.calls.argsFor(0)[0]).toContain( - 'Warning: %s\n\nThe fix is to split the update', - ); - expect(console.error.calls.argsFor(0)[1]).toContain( - 'A user-blocking update was suspended by:', + 'Warning: A user-blocking update was suspended by:', ); expect(console.error.calls.argsFor(0)[1]).toContain('AsyncText'); } From d19d4995cea41bdb73654803bdc2cc79dc8654d6 Mon Sep 17 00:00:00 2001 From: Luna Ruan Date: Wed, 31 Jul 2019 17:49:04 -0700 Subject: [PATCH 2/5] removed component that was suspended in error --- .../src/ReactFiberWorkLoop.js | 53 ++--------- .../__tests__/ReactSuspense-test.internal.js | 1 - ...tSuspenseWithNoopRenderer-test.internal.js | 92 ++++++------------- .../__tests__/ReactProfiler-test.internal.js | 9 -- 4 files changed, 32 insertions(+), 123 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 60a9558bb8f..f2d65ee7fb3 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -800,7 +800,6 @@ function prepareFreshStack(root, expirationTime) { if (__DEV__) { ReactStrictModeWarnings.discardPendingWarnings(); - componentsThatSuspendedAtHighPri = null; componentsThatTriggeredHighPriSuspend = null; } } @@ -2576,7 +2575,6 @@ export function warnIfUnmockedScheduler(fiber: Fiber) { } } -let componentsThatSuspendedAtHighPri = null; let componentsThatTriggeredHighPriSuspend = null; export function checkForWrongSuspensePriorityInDEV(sourceFiber: Fiber) { if (__DEV__) { @@ -2663,62 +2661,23 @@ export function checkForWrongSuspensePriorityInDEV(sourceFiber: Fiber) { } workInProgressNode = workInProgressNode.return; } - - // Add the component name to a set. - const componentName = getComponentName(sourceFiber.type); - if (componentsThatSuspendedAtHighPri === null) { - componentsThatSuspendedAtHighPri = new Set([componentName]); - } else { - componentsThatSuspendedAtHighPri.add(componentName); - } } } } function flushSuspensePriorityWarningInDEV() { if (__DEV__) { - if (componentsThatSuspendedAtHighPri !== null) { + if (componentsThatTriggeredHighPriSuspend !== null) { const componentNames = []; - componentsThatSuspendedAtHighPri.forEach(name => { - componentNames.push(name); - }); - componentsThatSuspendedAtHighPri = null; - - const componentsThatTriggeredSuspendNames = []; - if (componentsThatTriggeredHighPriSuspend !== null) { - componentsThatTriggeredHighPriSuspend.forEach(name => - componentsThatTriggeredSuspendNames.push(name), - ); - } - + componentsThatTriggeredHighPriSuspend.forEach(name => + componentNames.push(name), + ); componentsThatTriggeredHighPriSuspend = null; - const componentNamesString = componentNames.sort().join(', '); - if (componentsThatTriggeredSuspendNames.length > 0) { + if (componentNames.length > 0) { warningWithoutStack( false, 'The following components triggered a user-blocking update:' + - '\n\n' + - ' %s' + - '\n\n' + - 'that was then suspended by:' + - '\n\n' + - ' %s' + - '\n\n' + - 'The fix is to split the update into multiple parts: a user-blocking ' + - 'update to provide immediate feedback, and another update that ' + - 'triggers the bulk of the changes.' + - '\n\n' + - 'Refer to the documentation for useSuspenseTransition to learn how ' + - 'to implement this pattern.', - // TODO: Add link to React docs with more information, once it exists - componentsThatTriggeredSuspendNames.sort().join(', '), - componentNamesString, - ); - } else { - warningWithoutStack( - false, - 'A user-blocking update was suspended by:' + '\n\n' + ' %s' + '\n\n' + @@ -2729,7 +2688,7 @@ function flushSuspensePriorityWarningInDEV() { 'Refer to the documentation for useSuspenseTransition to learn how ' + 'to implement this pattern.', // TODO: Add link to React docs with more information, once it exists - componentNamesString, + componentNames.sort().join(', '), ); } } diff --git a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js index d7e3561ac95..32e8336d7c6 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js @@ -327,7 +327,6 @@ describe('ReactSuspense', () => { }); it('throws if tree suspends and none of the Suspense ancestors have a fallback', () => { - spyOnDev(console, 'error'); ReactTestRenderer.create( diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js index a3e0fd4c835..21c0832a579 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js @@ -660,19 +660,9 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(Scheduler).toHaveYielded(['Promise resolved [Async]']); expect(Scheduler).toFlushAndYield(['Async']); expect(ReactNoop.getChildren()).toEqual([span('Async'), span('Sync')]); - - if (__DEV__) { - expect(console.error).toHaveBeenCalledTimes(1); - expect(console.error.calls.argsFor(0)[0]).toContain( - 'Warning: A user-blocking update was suspended by:', - ); - expect(console.error.calls.argsFor(0)[1]).toContain('AsyncText'); - } }); it('suspending inside an expired expiration boundary will bubble to the next one', async () => { - spyOnDev(console, 'error'); - ReactNoop.flushSync(() => ReactNoop.render( @@ -693,14 +683,6 @@ describe('ReactSuspenseWithNoopRenderer', () => { ]); // The tree commits synchronously expect(ReactNoop.getChildren()).toEqual([span('Loading (outer)...')]); - - if (__DEV__) { - expect(console.error).toHaveBeenCalledTimes(1); - expect(console.error.calls.argsFor(0)[0]).toContain( - 'Warning: A user-blocking update was suspended by:', - ); - expect(console.error.calls.argsFor(0)[1]).toContain('AsyncText'); - } }); it('expires early by default', async () => { @@ -1609,18 +1591,11 @@ describe('ReactSuspenseWithNoopRenderer', () => { Scheduler.unstable_advanceTime(100); await advanceTimers(100); - expect(() => { - expect(Scheduler).toFlushAndYield([ - // A suspends - 'Suspend! [A]', - 'Loading...', - ]); - }).toWarnDev( - 'Warning: A user-blocking update was suspended by:' + - '\n\n' + - ' AsyncText', - {withoutStack: true}, - ); + expect(Scheduler).toFlushAndYield([ + // A suspends + 'Suspend! [A]', + 'Loading...', + ]); // We're now suspended and we haven't shown anything yet. expect(ReactNoop.getChildren()).toEqual([]); @@ -1664,10 +1639,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { 'Warning: The following components triggered a user-blocking update:' + '\n\n' + ' App' + - '\n\n' + - 'that was then suspended by:' + - '\n\n' + - ' AsyncText', + '\n\n', {withoutStack: true}, ); }); @@ -1702,15 +1674,12 @@ describe('ReactSuspenseWithNoopRenderer', () => { 'Warning: The following components triggered a user-blocking update:' + '\n\n' + ' App' + - '\n\n' + - 'that was then suspended by:' + - '\n\n' + - ' AsyncText', + '\n\n', {withoutStack: true}, ); }); - it('', async () => { + it('Does not warn when a component updates after the fallback is shown', async () => { let showB; class App extends React.Component { state = {showB: false}; @@ -1742,45 +1711,36 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(Scheduler).toHaveYielded(['Suspend! [A]', 'Suspend! [B]']); }); - it('warns when suspending inside discrete update', async () => { + it('Warns when component that triggered update is between Suspense boundary and component that threw', async () => { + let _setShow; function A() { - Scheduler.unstable_yieldValue('A'); - TextResource.read(['A', 1000]); - return 'A'; - } - - function B() { - return 'B'; - } - - function C() { - TextResource.read(['C', 1000]); - return 'C'; + const [show, setShow] = React.useState(false); + _setShow = setShow; + return show && ; } - function App() { return ( - - - - - ); } + await ReactNoop.act(async () => { + ReactNoop.render(); + }); - ReactNoop.discreteUpdates(() => ReactNoop.render()); - expect(Scheduler).toFlushAndYieldThrough(['A']); - - // Warning is not flushed until the commit phase - - // Timeout and commit the fallback expect(() => { - Scheduler.unstable_flushAll(); + ReactNoop.act(() => { + Scheduler.unstable_runWithPriority( + Scheduler.unstable_UserBlockingPriority, + () => _setShow(true), + ); + }); }).toWarnDev( - 'Warning: A user-blocking update was suspended by:' + '\n\n' + ' A, C', + 'Warning: The following components triggered a user-blocking update:' + + '\n\n' + + ' A' + + '\n\n', {withoutStack: true}, ); }); diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js index 2237249cd7f..9edad199ef4 100644 --- a/packages/react/src/__tests__/ReactProfiler-test.internal.js +++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js @@ -2626,7 +2626,6 @@ describe('Profiler', () => { }); it('handles high-pri renderers between suspended and resolved (async) trees', async () => { - spyOnDev(console, 'error'); // Set up an initial shell. We need to set this up before the test sceanrio // because we want initial render to suspend on navigation to the initial state. let renderer = ReactTestRenderer.create( @@ -2729,14 +2728,6 @@ describe('Profiler', () => { expect( onInteractionScheduledWorkCompleted.mock.calls[1][0], ).toMatchInteraction(highPriUpdateInteraction); - - if (__DEV__) { - expect(console.error).toHaveBeenCalledTimes(1); - expect(console.error.calls.argsFor(0)[0]).toContain( - 'Warning: A user-blocking update was suspended by:', - ); - expect(console.error.calls.argsFor(0)[1]).toContain('AsyncText'); - } }); }); }); From 8f8f7a0123db1b12c2cd8aeac087c1512104af6a Mon Sep 17 00:00:00 2001 From: Luna Ruan Date: Wed, 31 Jul 2019 17:51:52 -0700 Subject: [PATCH 3/5] reworded test --- .../__tests__/ReactSuspenseWithNoopRenderer-test.internal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js index 21c0832a579..2913c16129e 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js @@ -1711,7 +1711,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(Scheduler).toHaveYielded(['Suspend! [A]', 'Suspend! [B]']); }); - it('Warns when component that triggered update is between Suspense boundary and component that threw', async () => { + it('Warns when component that triggered update is between Suspense boundary and component that suspended', async () => { let _setShow; function A() { const [show, setShow] = React.useState(false); From 432db598ea216a0b5330589115e4edbc5a68b8b3 Mon Sep 17 00:00:00 2001 From: Luna Ruan Date: Wed, 31 Jul 2019 19:00:30 -0700 Subject: [PATCH 4/5] fixed lint error --- ...tSuspenseWithNoopRenderer-test.internal.js | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js index 2913c16129e..500d9b72d10 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js @@ -1711,39 +1711,43 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(Scheduler).toHaveYielded(['Suspend! [A]', 'Suspend! [B]']); }); - it('Warns when component that triggered update is between Suspense boundary and component that suspended', async () => { - let _setShow; - function A() { - const [show, setShow] = React.useState(false); - _setShow = setShow; - return show && ; - } - function App() { - return ( - - - - ); - } - await ReactNoop.act(async () => { - ReactNoop.render(); - }); - - expect(() => { - ReactNoop.act(() => { - Scheduler.unstable_runWithPriority( - Scheduler.unstable_UserBlockingPriority, - () => _setShow(true), + it( + 'Warns when component that triggered update is between Suspense boundary ' + + 'and component that suspended', + async () => { + let _setShow; + function A() { + const [show, setShow] = React.useState(false); + _setShow = setShow; + return show && ; + } + function App() { + return ( + + + ); + } + await ReactNoop.act(async () => { + ReactNoop.render(); }); - }).toWarnDev( - 'Warning: The following components triggered a user-blocking update:' + - '\n\n' + - ' A' + - '\n\n', - {withoutStack: true}, - ); - }); + + expect(() => { + ReactNoop.act(() => { + Scheduler.unstable_runWithPriority( + Scheduler.unstable_UserBlockingPriority, + () => _setShow(true), + ); + }); + }).toWarnDev( + 'Warning: The following components triggered a user-blocking update:' + + '\n\n' + + ' A' + + '\n\n', + {withoutStack: true}, + ); + }, + ); it('normal priority updates suspending do not warn for class components', async () => { let show; From c22465d7975bd69a50dfde97728f6b5862da8cb6 Mon Sep 17 00:00:00 2001 From: Luna Ruan Date: Fri, 2 Aug 2019 11:39:57 -0700 Subject: [PATCH 5/5] renamed a bunch of things and updated test to be more specific --- .../src/ReactFiberWorkLoop.js | 4 +--- ...tSuspenseWithNoopRenderer-test.internal.js | 20 ++++++------------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index f2d65ee7fb3..6ce6f61430a 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -2677,9 +2677,7 @@ function flushSuspensePriorityWarningInDEV() { if (componentNames.length > 0) { warningWithoutStack( false, - 'The following components triggered a user-blocking update:' + - '\n\n' + - ' %s' + + '%s triggered a user-blocking update that suspended.' + '\n\n' + 'The fix is to split the update into multiple parts: a user-blocking ' + 'update to provide immediate feedback, and another update that ' + diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js index 500d9b72d10..b2a2a7c5393 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js @@ -1636,10 +1636,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); }); }).toWarnDev( - 'Warning: The following components triggered a user-blocking update:' + - '\n\n' + - ' App' + - '\n\n', + 'Warning: App triggered a user-blocking update that suspended.' + '\n\n', {withoutStack: true}, ); }); @@ -1671,15 +1668,12 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); }); }).toWarnDev( - 'Warning: The following components triggered a user-blocking update:' + - '\n\n' + - ' App' + - '\n\n', + 'Warning: App triggered a user-blocking update that suspended.' + '\n\n', {withoutStack: true}, ); }); - it('Does not warn when a component updates after the fallback is shown', async () => { + it('does not warn about wrong Suspense priority if no new fallbacks are shown', async () => { let showB; class App extends React.Component { state = {showB: false}; @@ -1700,6 +1694,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { }); expect(Scheduler).toHaveYielded(['Suspend! [A]']); + expect(ReactNoop).toMatchRenderedOutput('Loading...'); ReactNoop.act(() => { Scheduler.unstable_runWithPriority( @@ -1712,7 +1707,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { }); it( - 'Warns when component that triggered update is between Suspense boundary ' + + 'warns when component that triggered user-blocking update is between Suspense boundary ' + 'and component that suspended', async () => { let _setShow; @@ -1740,10 +1735,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); }); }).toWarnDev( - 'Warning: The following components triggered a user-blocking update:' + - '\n\n' + - ' A' + - '\n\n', + 'Warning: A triggered a user-blocking update that suspended.' + '\n\n', {withoutStack: true}, ); },