@@ -2184,4 +2184,87 @@ describe('ReactIncremental', () => {
2184
2184
'componentDidUpdate' ,
2185
2185
] ) ;
2186
2186
} ) ;
2187
+
2188
+ it ( 'should reuse memoized work if pointers are updated before calling lifecycles' , ( ) => {
2189
+ let cduNextProps = [ ] ;
2190
+ let cduPrevProps = [ ] ;
2191
+ let scuNextProps = [ ] ;
2192
+ let scuPrevProps = [ ] ;
2193
+ let renderCounter = 0 ;
2194
+
2195
+ function SecondChild ( props ) {
2196
+ return < span > { props . children } </ span > ;
2197
+ }
2198
+
2199
+ class FirstChild extends React . Component {
2200
+ componentDidUpdate ( prevProps , prevState ) {
2201
+ cduNextProps . push ( this . props ) ;
2202
+ cduPrevProps . push ( prevProps ) ;
2203
+ }
2204
+ shouldComponentUpdate ( nextProps , nextState ) {
2205
+ scuNextProps . push ( nextProps ) ;
2206
+ scuPrevProps . push ( this . props ) ;
2207
+ return this . props . children !== nextProps . children ;
2208
+ }
2209
+ render ( ) {
2210
+ renderCounter ++ ;
2211
+ return < span > { this . props . children } </ span > ;
2212
+ }
2213
+ }
2214
+
2215
+ class Middle extends React . Component {
2216
+ render ( ) {
2217
+ return (
2218
+ < div >
2219
+ < FirstChild > { this . props . children } </ FirstChild >
2220
+ < SecondChild > { this . props . children } </ SecondChild >
2221
+ </ div >
2222
+ ) ;
2223
+ }
2224
+ }
2225
+
2226
+ function Root ( props ) {
2227
+ return (
2228
+ < div hidden = { true } >
2229
+ < Middle { ...props } />
2230
+ </ div >
2231
+ ) ;
2232
+ }
2233
+
2234
+ // Initial render of the entire tree.
2235
+ // Renders: Root, Middle, FirstChild, SecondChild
2236
+ ReactNoop . render ( < Root > A</ Root > ) ;
2237
+ ReactNoop . flush ( ) ;
2238
+
2239
+ expect ( renderCounter ) . toBe ( 1 ) ;
2240
+
2241
+ // Schedule low priority work to update children.
2242
+ // Give it enough time to partially render.
2243
+ // Renders: Root, Middle, FirstChild
2244
+ ReactNoop . render ( < Root > B</ Root > ) ;
2245
+ ReactNoop . flushDeferredPri ( 20 + 30 + 5 ) ;
2246
+
2247
+ // At this point our FirstChild component has rendered a second time,
2248
+ // But since the render is not completed cDU should not be called yet.
2249
+ expect ( renderCounter ) . toBe ( 2 ) ;
2250
+ expect ( scuPrevProps ) . toEqual ( [ { children : 'A' } ] ) ;
2251
+ expect ( scuNextProps ) . toEqual ( [ { children : 'B' } ] ) ;
2252
+ expect ( cduPrevProps ) . toEqual ( [ ] ) ;
2253
+ expect ( cduNextProps ) . toEqual ( [ ] ) ;
2254
+
2255
+ // Next interrupt the partial render with higher priority work.
2256
+ // The in-progress child content will bailout.
2257
+ // Renders: Root, Middle, FirstChild, SecondChild
2258
+ ReactNoop . render ( < Root > B</ Root > ) ;
2259
+ ReactNoop . flush ( ) ;
2260
+
2261
+ // At this point the higher priority render has completed.
2262
+ // Since FirstChild props didn't change, sCU returned false.
2263
+ // The previous memoized copy should be used.
2264
+ expect ( renderCounter ) . toBe ( 2 ) ;
2265
+ expect ( scuPrevProps ) . toEqual ( [ { children : 'A' } , { children : 'B' } ] ) ;
2266
+ expect ( scuNextProps ) . toEqual ( [ { children : 'B' } , { children : 'B' } ] ) ;
2267
+ expect ( cduPrevProps ) . toEqual ( [ { children : 'A' } ] ) ;
2268
+ expect ( cduNextProps ) . toEqual ( [ { children : 'B' } ] ) ;
2269
+ } ) ;
2187
2270
} ) ;
0 commit comments