File tree Expand file tree Collapse file tree 2 files changed +35
-5
lines changed
Expand file tree Collapse file tree 2 files changed +35
-5
lines changed Original file line number Diff line number Diff line change @@ -447,13 +447,14 @@ export function useId() {
447447function flushAfterPaintEffects ( ) {
448448 let component ;
449449 while ( ( component = afterPaintEffects . shift ( ) ) ) {
450- if ( ! component . _parentDom || ! component . __hooks ) continue ;
450+ const hooks = component . __hooks ;
451+ if ( ! component . _parentDom || ! hooks ) continue ;
451452 try {
452- component . __hooks . _pendingEffects . some ( invokeCleanup ) ;
453- component . __hooks . _pendingEffects . some ( invokeEffect ) ;
454- component . __hooks . _pendingEffects = [ ] ;
453+ hooks . _pendingEffects . some ( invokeCleanup ) ;
454+ hooks . _pendingEffects . some ( invokeEffect ) ;
455+ hooks . _pendingEffects = [ ] ;
455456 } catch ( e ) {
456- component . __hooks . _pendingEffects = [ ] ;
457+ hooks . _pendingEffects = [ ] ;
457458 options . _catchError ( e , component . _vnode ) ;
458459 }
459460 }
Original file line number Diff line number Diff line change @@ -636,4 +636,33 @@ describe('useEffect', () => {
636636 expect ( calls . length ) . to . equal ( 1 ) ;
637637 expect ( calls ) . to . deep . equal ( [ 'doing effecthi' ] ) ;
638638 } ) ;
639+
640+ it ( 'should not crash when effect throws and component is unmounted by render(null) during flush' , ( ) => {
641+ // In flushAfterPaintEffects():
642+ // 1. Guard checks component.__hooks — truthy, passes
643+ // 2. invokeEffect runs the effect callback
644+ // 3. The callback calls render(null, scratch) which unmounts the tree
645+ // → options.unmount sets component.__hooks = undefined
646+ // 4. Resetting the hooks array to an empty array would throw an error
647+ let setVal ;
648+
649+ function App ( ) {
650+ const [ val , _setVal ] = useState ( 0 ) ;
651+ setVal = _setVal ;
652+ useEffect ( ( ) => {
653+ if ( val === 1 ) {
654+ render ( null , scratch ) ;
655+ }
656+ } , [ val ] ) ;
657+ return < div > val: { val } </ div > ;
658+ }
659+
660+ act ( ( ) => {
661+ render ( < App /> , scratch ) ;
662+ } ) ;
663+
664+ act ( ( ) => {
665+ setVal ( 1 ) ;
666+ } ) ;
667+ } ) ;
639668} ) ;
You can’t perform that action at this time.
0 commit comments