@@ -226,4 +226,131 @@ describe('forwardRef', () => {
226
226
' in Foo (at **)' ,
227
227
) ;
228
228
} ) ;
229
+
230
+ it ( 'should not bailout if forwardRef is not wrapped in pure' , ( ) => {
231
+ const Component = props => < div { ...props } /> ;
232
+
233
+ let renderCount = 0 ;
234
+
235
+ const RefForwardingComponent = React . forwardRef ( ( props , ref ) => {
236
+ renderCount ++ ;
237
+ return < Component { ...props } forwardedRef = { ref } /> ;
238
+ } ) ;
239
+
240
+ const ref = React . createRef ( ) ;
241
+
242
+ ReactNoop . render ( < RefForwardingComponent ref = { ref } optional = "foo" /> ) ;
243
+ ReactNoop . flush ( ) ;
244
+ expect ( renderCount ) . toBe ( 1 ) ;
245
+
246
+ ReactNoop . render ( < RefForwardingComponent ref = { ref } optional = "foo" /> ) ;
247
+ ReactNoop . flush ( ) ;
248
+ expect ( renderCount ) . toBe ( 2 ) ;
249
+ } ) ;
250
+
251
+ it ( 'should bailout if forwardRef is wrapped in pure' , ( ) => {
252
+ const Component = props => < div ref = { props . forwardedRef } /> ;
253
+
254
+ let renderCount = 0 ;
255
+
256
+ const RefForwardingComponent = React . pure (
257
+ React . forwardRef ( ( props , ref ) => {
258
+ renderCount ++ ;
259
+ return < Component { ...props } forwardedRef = { ref } /> ;
260
+ } ) ,
261
+ ) ;
262
+
263
+ const ref = React . createRef ( ) ;
264
+
265
+ ReactNoop . render ( < RefForwardingComponent ref = { ref } optional = "foo" /> ) ;
266
+ ReactNoop . flush ( ) ;
267
+ expect ( renderCount ) . toBe ( 1 ) ;
268
+
269
+ expect ( ref . current . type ) . toBe ( 'div' ) ;
270
+
271
+ ReactNoop . render ( < RefForwardingComponent ref = { ref } optional = "foo" /> ) ;
272
+ ReactNoop . flush ( ) ;
273
+ expect ( renderCount ) . toBe ( 1 ) ;
274
+
275
+ const differentRef = React . createRef ( ) ;
276
+
277
+ ReactNoop . render (
278
+ < RefForwardingComponent ref = { differentRef } optional = "foo" /> ,
279
+ ) ;
280
+ ReactNoop . flush ( ) ;
281
+ expect ( renderCount ) . toBe ( 2 ) ;
282
+
283
+ expect ( ref . current ) . toBe ( null ) ;
284
+ expect ( differentRef . current . type ) . toBe ( 'div' ) ;
285
+
286
+ ReactNoop . render ( < RefForwardingComponent ref = { ref } optional = "bar" /> ) ;
287
+ ReactNoop . flush ( ) ;
288
+ expect ( renderCount ) . toBe ( 3 ) ;
289
+ } ) ;
290
+
291
+ it ( 'should custom pure comparisons to compose' , ( ) => {
292
+ const Component = props => < div ref = { props . forwardedRef } /> ;
293
+
294
+ let renderCount = 0 ;
295
+
296
+ const RefForwardingComponent = React . pure (
297
+ React . forwardRef ( ( props , ref ) => {
298
+ renderCount ++ ;
299
+ return < Component { ...props } forwardedRef = { ref } /> ;
300
+ } ) ,
301
+ ( o , p ) => o . a === p . a && o . b === p . b ,
302
+ ) ;
303
+
304
+ const ref = React . createRef ( ) ;
305
+
306
+ ReactNoop . render ( < RefForwardingComponent ref = { ref } a = "0" b = "0" c = "1" /> ) ;
307
+ ReactNoop . flush ( ) ;
308
+ expect ( renderCount ) . toBe ( 1 ) ;
309
+
310
+ expect ( ref . current . type ) . toBe ( 'div' ) ;
311
+
312
+ // Changing either a or b rerenders
313
+ ReactNoop . render ( < RefForwardingComponent ref = { ref } a = "0" b = "1" c = "1" /> ) ;
314
+ ReactNoop . flush ( ) ;
315
+ expect ( renderCount ) . toBe ( 2 ) ;
316
+
317
+ // Changing c doesn't rerender
318
+ ReactNoop . render ( < RefForwardingComponent ref = { ref } a = "0" b = "1" c = "2" /> ) ;
319
+ ReactNoop . flush ( ) ;
320
+ expect ( renderCount ) . toBe ( 2 ) ;
321
+
322
+ const ComposedPure = React . pure (
323
+ RefForwardingComponent ,
324
+ ( o , p ) => o . a === p . a && o . c === p . c ,
325
+ ) ;
326
+
327
+ ReactNoop . render ( < ComposedPure ref = { ref } a = "0" b = "0" c = "0" /> ) ;
328
+ ReactNoop . flush ( ) ;
329
+ expect ( renderCount ) . toBe ( 3 ) ;
330
+
331
+ // Changing just b no longer updates
332
+ ReactNoop . render ( < ComposedPure ref = { ref } a = "0" b = "1" c = "0" /> ) ;
333
+ ReactNoop . flush ( ) ;
334
+ expect ( renderCount ) . toBe ( 3 ) ;
335
+
336
+ // Changing just a and c updates
337
+ ReactNoop . render ( < ComposedPure ref = { ref } a = "2" b = "2" c = "2" /> ) ;
338
+ ReactNoop . flush ( ) ;
339
+ expect ( renderCount ) . toBe ( 4 ) ;
340
+
341
+ // Changing just c does not update
342
+ ReactNoop . render ( < ComposedPure ref = { ref } a = "2" b = "2" c = "3" /> ) ;
343
+ ReactNoop . flush ( ) ;
344
+ expect ( renderCount ) . toBe ( 4 ) ;
345
+
346
+ // Changing ref still rerenders
347
+ const differentRef = React . createRef ( ) ;
348
+
349
+ ReactNoop . render ( < ComposedPure ref = { differentRef } a = "2" b = "2" c = "3" /> ) ;
350
+ ReactNoop . flush ( ) ;
351
+ expect ( renderCount ) . toBe ( 5 ) ;
352
+
353
+ expect ( ref . current ) . toBe ( null ) ;
354
+ expect ( differentRef . current . type ) . toBe ( 'div' ) ;
355
+ } ) ;
229
356
} ) ;
0 commit comments