@@ -752,4 +752,97 @@ describe('ProfilingCache', () => {
752752 utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
753753 expect ( container . textContent ) . toBe ( 'About' ) ;
754754 } ) ;
755+
756+ it ( 'components that were deleted and added to updaters during the layout phase should not crash' , ( ) => {
757+ let setChildUnmounted ;
758+ function Child ( ) {
759+ const [ , setState ] = React . useState ( false ) ;
760+
761+ React . useLayoutEffect ( ( ) => {
762+ return ( ) => setState ( true ) ;
763+ } ) ;
764+
765+ return null ;
766+ }
767+
768+ function App ( ) {
769+ const [ childUnmounted , _setChildUnmounted ] = React . useState ( false ) ;
770+ setChildUnmounted = _setChildUnmounted ;
771+ return < > { ! childUnmounted && < Child /> } </ > ;
772+ }
773+
774+ const root = ReactDOM . createRoot ( document . createElement ( 'div' ) ) ;
775+ utils . act ( ( ) => root . render ( < App /> ) ) ;
776+ utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
777+ utils . act ( ( ) => setChildUnmounted ( true ) ) ;
778+ utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
779+
780+ const updaters = store . profilerStore . getCommitData ( store . roots [ 0 ] , 0 )
781+ . updaters ;
782+ expect ( updaters . length ) . toEqual ( 1 ) ;
783+ expect ( updaters [ 0 ] . displayName ) . toEqual ( 'App' ) ;
784+ } ) ;
785+
786+ it ( 'components in a deleted subtree and added to updaters during the layout phase should not crash' , ( ) => {
787+ let setChildUnmounted ;
788+ function Child ( ) {
789+ return < GrandChild /> ;
790+ }
791+
792+ function GrandChild ( ) {
793+ const [ , setState ] = React . useState ( false ) ;
794+
795+ React . useLayoutEffect ( ( ) => {
796+ return ( ) => setState ( true ) ;
797+ } ) ;
798+
799+ return null ;
800+ }
801+
802+ function App ( ) {
803+ const [ childUnmounted , _setChildUnmounted ] = React . useState ( false ) ;
804+ setChildUnmounted = _setChildUnmounted ;
805+ return < > { ! childUnmounted && < Child /> } </ > ;
806+ }
807+
808+ const root = ReactDOM . createRoot ( document . createElement ( 'div' ) ) ;
809+ utils . act ( ( ) => root . render ( < App /> ) ) ;
810+ utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
811+ utils . act ( ( ) => setChildUnmounted ( true ) ) ;
812+ utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
813+
814+ const updaters = store . profilerStore . getCommitData ( store . roots [ 0 ] , 0 )
815+ . updaters ;
816+ expect ( updaters . length ) . toEqual ( 1 ) ;
817+ expect ( updaters [ 0 ] . displayName ) . toEqual ( 'App' ) ;
818+ } ) ;
819+
820+ it ( 'components that were deleted should not be added to updaters during the passive phase' , ( ) => {
821+ let setChildUnmounted ;
822+ function Child ( ) {
823+ const [ , setState ] = React . useState ( false ) ;
824+ React . useEffect ( ( ) => {
825+ return ( ) => setState ( true ) ;
826+ } ) ;
827+
828+ return null ;
829+ }
830+
831+ function App ( ) {
832+ const [ childUnmounted , _setChildUnmounted ] = React . useState ( false ) ;
833+ setChildUnmounted = _setChildUnmounted ;
834+ return < > { ! childUnmounted && < Child /> } </ > ;
835+ }
836+
837+ const root = ReactDOM . createRoot ( document . createElement ( 'div' ) ) ;
838+ utils . act ( ( ) => root . render ( < App /> ) ) ;
839+ utils . act ( ( ) => store . profilerStore . startProfiling ( ) ) ;
840+ utils . act ( ( ) => setChildUnmounted ( true ) ) ;
841+ utils . act ( ( ) => store . profilerStore . stopProfiling ( ) ) ;
842+
843+ const updaters = store . profilerStore . getCommitData ( store . roots [ 0 ] , 0 )
844+ . updaters ;
845+ expect ( updaters . length ) . toEqual ( 1 ) ;
846+ expect ( updaters [ 0 ] . displayName ) . toEqual ( 'App' ) ;
847+ } ) ;
755848} ) ;
0 commit comments