diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js index 15c7b9e5f19a3..86fb78244188d 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js @@ -1512,6 +1512,165 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); }); + it('does not call lifecycles of a suspended component (hooks)', async () => { + function TextWithLifecycle(props) { + React.useLayoutEffect( + () => { + Scheduler.unstable_yieldValue(`Layout Effect [${props.text}]`); + return () => { + Scheduler.unstable_yieldValue( + `Destroy Layout Effect [${props.text}]`, + ); + }; + }, + [props.text], + ); + React.useEffect( + () => { + Scheduler.unstable_yieldValue(`Effect [${props.text}]`); + return () => { + Scheduler.unstable_yieldValue(`Destroy Effect [${props.text}]`); + }; + }, + [props.text], + ); + return ; + } + + function AsyncTextWithLifecycle(props) { + React.useLayoutEffect( + () => { + Scheduler.unstable_yieldValue(`Layout Effect [${props.text}]`); + return () => { + Scheduler.unstable_yieldValue( + `Destroy Layout Effect [${props.text}]`, + ); + }; + }, + [props.text], + ); + React.useEffect( + () => { + Scheduler.unstable_yieldValue(`Effect [${props.text}]`); + return () => { + Scheduler.unstable_yieldValue(`Destroy Effect [${props.text}]`); + }; + }, + [props.text], + ); + const text = props.text; + const ms = props.ms; + try { + TextResource.read([text, ms]); + Scheduler.unstable_yieldValue(text); + return ; + } catch (promise) { + if (typeof promise.then === 'function') { + Scheduler.unstable_yieldValue(`Suspend! [${text}]`); + } else { + Scheduler.unstable_yieldValue(`Error! [${text}]`); + } + throw promise; + } + } + + function App({text}) { + return ( + }> + + + + + ); + } + + ReactNoop.renderLegacySyncRoot(, () => + Scheduler.unstable_yieldValue('Commit root'), + ); + expect(Scheduler).toHaveYielded([ + 'A', + 'Suspend! [B]', + 'C', + 'Loading...', + + 'Layout Effect [A]', + // B's effect should not fire because it suspended + // 'Layout Effect [B]', + 'Layout Effect [C]', + 'Layout Effect [Loading...]', + 'Commit root', + ]); + + // Flush passive effects. + expect(Scheduler).toFlushAndYield([ + 'Effect [A]', + // B's effect should not fire because it suspended + // 'Effect [B]', + 'Effect [C]', + 'Effect [Loading...]', + ]); + + expect(ReactNoop).toMatchRenderedOutput( + <> +