@@ -2734,6 +2734,75 @@ describe('ReactHooksWithNoopRenderer', () => {
27342734 expect ( ReactNoop . getChildren ( ) ) . toEqual ( [ ] ) ;
27352735 } ) ;
27362736 } ) ;
2737+
2738+ it ( 'calls passive effect destroy functions for memoized components' , ( ) => {
2739+ const Wrapper = ( { children} ) => children ;
2740+ function Child ( { prop} ) {
2741+ React . useEffect ( ( ) => {
2742+ Scheduler . unstable_yieldValue ( 'passive create' ) ;
2743+ return ( ) => {
2744+ Scheduler . unstable_yieldValue ( 'passive destroy' ) ;
2745+ } ;
2746+ } , [ prop ] ) ;
2747+ React . useLayoutEffect ( ( ) => {
2748+ Scheduler . unstable_yieldValue ( 'layout create' ) ;
2749+ return ( ) => {
2750+ Scheduler . unstable_yieldValue ( 'layout destroy' ) ;
2751+ } ;
2752+ } , [ prop ] ) ;
2753+ Scheduler . unstable_yieldValue ( 'render' ) ;
2754+ return null ;
2755+ }
2756+
2757+ const isEqual = ( prevProps , nextProps ) =>
2758+ prevProps . prop === nextProps . prop ;
2759+ const MemoizedChild = React . memo ( Child , isEqual ) ;
2760+
2761+ act ( ( ) => {
2762+ ReactNoop . render (
2763+ < Wrapper >
2764+ < MemoizedChild key = { 1 } />
2765+ </ Wrapper > ,
2766+ ) ;
2767+ } ) ;
2768+ expect ( Scheduler ) . toHaveYielded ( [
2769+ 'render' ,
2770+ 'layout create' ,
2771+ 'passive create' ,
2772+ ] ) ;
2773+
2774+ act ( ( ) => {
2775+ ReactNoop . render (
2776+ < Wrapper >
2777+ < MemoizedChild key = { 1 } />
2778+ </ Wrapper > ,
2779+ ) ;
2780+ } ) ;
2781+ expect ( Scheduler ) . toHaveYielded ( [ ] ) ;
2782+
2783+ // This update is exists to test an internal implementation detail:
2784+ // Effects without updating dependencies lose their layout/passive tag during an update.
2785+ act ( ( ) => {
2786+ ReactNoop . render (
2787+ < Wrapper >
2788+ < MemoizedChild key = { 2 } />
2789+ </ Wrapper > ,
2790+ ) ;
2791+ } ) ;
2792+ expect ( Scheduler ) . toHaveYielded ( [
2793+ 'render' ,
2794+ 'layout destroy' ,
2795+ 'layout create' ,
2796+ 'passive destroy' ,
2797+ 'passive create' ,
2798+ ] ) ;
2799+
2800+ // Unmount the component and verify that passive destroy functions are deferred until post-commit.
2801+ act ( ( ) => {
2802+ ReactNoop . render ( null ) ;
2803+ } ) ;
2804+ expect ( Scheduler ) . toHaveYielded ( [ 'layout destroy' , 'passive destroy' ] ) ;
2805+ } ) ;
27372806 } ) ;
27382807
27392808 describe ( 'useLayoutEffect' , ( ) => {
0 commit comments