File tree Expand file tree Collapse file tree 2 files changed +65
-0
lines changed Expand file tree Collapse file tree 2 files changed +65
-0
lines changed Original file line number Diff line number Diff line change @@ -97,6 +97,64 @@ describe('suspense hydration', () => {
9797 } ) ;
9898 } ) ;
9999
100+ it ( 'Should not crash when oldVNode._children is null during shouldComponentUpdate optimization' , ( ) => {
101+ const originalHtml = '<div>Hello</div>' ;
102+ scratch . innerHTML = originalHtml ;
103+ clearLog ( ) ;
104+
105+ class ErrorBoundary extends React . Component {
106+ constructor ( props ) {
107+ super ( props ) ;
108+ this . state = { hasError : false } ;
109+ }
110+
111+ static getDerivedStateFromError ( ) {
112+ return { hasError : true } ;
113+ }
114+
115+ render ( ) {
116+ return this . props . children ;
117+ }
118+ }
119+
120+ const [ Lazy , resolve ] = createLazy ( ) ;
121+ function App ( ) {
122+ return (
123+ < Suspense >
124+ < ErrorBoundary >
125+ < Lazy />
126+ </ ErrorBoundary >
127+ </ Suspense >
128+ ) ;
129+ }
130+
131+ hydrate ( < App /> , scratch ) ;
132+ rerender ( ) ; // Flush rerender queue to mimic what preact will really do
133+ expect ( scratch . innerHTML ) . to . equal ( originalHtml ) ;
134+ expect ( getLog ( ) ) . to . deep . equal ( [ ] ) ;
135+ clearLog ( ) ;
136+
137+ let i = 0 ;
138+ class ThrowOrRender extends React . Component {
139+ shouldComponentUpdate ( ) {
140+ return i === 0 ;
141+ }
142+ render ( ) {
143+ if ( i === 0 ) {
144+ i ++ ;
145+ throw new Error ( 'Test error' ) ;
146+ }
147+ return < div > Hello</ div > ;
148+ }
149+ }
150+
151+ return resolve ( ThrowOrRender ) . then ( ( ) => {
152+ rerender ( ) ;
153+ expect ( scratch . innerHTML ) . to . equal ( originalHtml ) ;
154+ clearLog ( ) ;
155+ } ) ;
156+ } ) ;
157+
100158 it ( 'should leave DOM untouched when suspending while hydrating' , ( ) => {
101159 scratch . innerHTML = '<!-- test --><div>Hello</div>' ;
102160 clearLog ( ) ;
Original file line number Diff line number Diff line change @@ -309,10 +309,12 @@ export function diff(
309309 for ( let i = excessDomChildren . length ; i -- ; ) {
310310 removeNode ( excessDomChildren [ i ] ) ;
311311 }
312+ markAsForce ( newVNode ) ;
312313 }
313314 } else {
314315 newVNode . _dom = oldVNode . _dom ;
315316 newVNode . _children = oldVNode . _children ;
317+ markAsForce ( newVNode ) ;
316318 }
317319 options . _catchError ( e , newVNode , oldVNode ) ;
318320 }
@@ -341,6 +343,11 @@ export function diff(
341343 return newVNode . _flags & MODE_SUSPENDED ? undefined : oldDom ;
342344}
343345
346+ function markAsForce ( vnode ) {
347+ if ( vnode && vnode . _component ) vnode . _component . _force = true ;
348+ if ( vnode && vnode . _children ) vnode . _children . forEach ( markAsForce ) ;
349+ }
350+
344351/**
345352 * @param {Array<Component> } commitQueue List of components
346353 * which have callbacks to invoke in commitRoot
You can’t perform that action at this time.
0 commit comments