@@ -259,3 +259,79 @@ it("should be able to render without mock defaults", async () => {
259
259
await delay ( 50 ) ;
260
260
assertSize ( { width : 100 , height : 100 } ) ;
261
261
} ) ;
262
+
263
+ it ( "should not trigger unnecessary renders with the same width or height" , async ( ) => {
264
+ const Test = ( { resolveHandler } ) => {
265
+ return (
266
+ < div style = { { position : "relative" } } id = "container" >
267
+ < Observed resolveHandler = { resolveHandler } />
268
+ </ div >
269
+ ) ;
270
+ } ;
271
+
272
+ // Setting the size like this won't trigger any unnecessary re-renders within
273
+ // the components, so we can accurately measure renders being triggered by the
274
+ // hook itself.
275
+ const setSize = ( { width, height } ) => {
276
+ const container = document . querySelector ( "#container" ) ;
277
+ container . style . width = `${ width } px` ;
278
+ container . style . height = `${ height } px` ;
279
+ } ;
280
+ const { assertSize, assertRenderCount } = await render ( Test ) ;
281
+
282
+ assertSize ( { width : 1 , height : 1 } ) ;
283
+ assertRenderCount ( 1 ) ;
284
+
285
+ await delay ( 50 ) ;
286
+ assertRenderCount ( 2 ) ;
287
+
288
+ setSize ( { width : 100 , height : 102 } ) ;
289
+ await delay ( 50 ) ;
290
+ assertSize ( { width : 100 , height : 102 } ) ;
291
+ assertRenderCount ( 3 ) ;
292
+
293
+ // Shouldn't trigger on subpixel values that are rounded to be the same as the
294
+ // previous size
295
+ setSize ( { width : 100.4 , height : 102.4 } ) ;
296
+ await delay ( 50 ) ;
297
+ assertSize ( { width : 100 , height : 102 } ) ;
298
+ assertRenderCount ( 3 ) ;
299
+ } ) ;
300
+
301
+ it ( "should keep the same response instance between renders if nothing changed" , async ( ) => {
302
+ const Test = ( { resolveHandler } ) => {
303
+ const previousResponseRef = useRef ( null ) ;
304
+ const response = useResizeObserver ( { useDefaults : false } ) ;
305
+ const [ state , setState ] = useState ( false ) ;
306
+
307
+ const sameInstance = previousResponseRef . current === response ;
308
+ previousResponseRef . current = response ;
309
+
310
+ useEffect ( ( ) => {
311
+ if ( response . width && response . height ) {
312
+ // Triggering an extra render once the hook properly measured the element size once.
313
+ // This'll allow us to see if the hook keeps the same response object or not.
314
+ setState ( true ) ;
315
+ }
316
+ } , [ response ] ) ;
317
+
318
+ useEffect ( ( ) => {
319
+ if ( ! state ) {
320
+ return ;
321
+ }
322
+
323
+ // Everything is set up, ready for assertions
324
+ resolveHandler ( {
325
+ assertSameInstance : ( ) => {
326
+ expect ( sameInstance ) . toBe ( true ) ;
327
+ }
328
+ } ) ;
329
+ } , [ state ] ) ;
330
+
331
+ return < div ref = { response . ref } > { String ( sameInstance ) } </ div > ;
332
+ } ;
333
+
334
+ const { assertSameInstance } = await render ( Test ) ;
335
+
336
+ assertSameInstance ( ) ;
337
+ } ) ;
0 commit comments