@@ -396,6 +396,19 @@ const young = useTrackedState().person.age < 11;
396
396
397
397
Whereas with useTrackedState, a component re-renders whenever the ` age ` value is changed.
398
398
399
+ #### How to debug
400
+
401
+ Unlike useSelector, useTrackedState's behavior may seem like a magic.
402
+ Disclosing the tracked information stored in useTrackedState could mitigate it.
403
+ While useSelector shows the selected state with useDebugValue,
404
+ useTrackedState shows the tracked state paths with useDebugValue.
405
+
406
+ By using React Developer Tools, you can investigate the tracked
407
+ information in the hook. It is inside ` AffectedDebugValue ` .
408
+ If you experience extra re-renders or missing re-renders,
409
+ you can check the tracked state paths which may help finding bugs
410
+ in your application code or possible bugs in the library code.
411
+
399
412
#### Caveats
400
413
401
414
Proxy-based tracking has limitations.
@@ -427,17 +440,31 @@ const Child = React.memo(({ foo }) => {
427
440
428
441
It's recommended to use primitive values for props with memo'd components.
429
442
430
- - Proxied state shouldn't be used outside of render
443
+ - Proxied state might behave unexpectedly outside render
444
+
445
+ Proxies are basically transparent, and it should behave like normal objects.
446
+ However, there can be edge cases where it behaves unexpectedly.
447
+ For example, if you console.log a proxied value,
448
+ it will display a proxy wrapping an object.
449
+ Notice, it will be kept tracking outside render,
450
+ so any prorerty access will mark as used to trigger re-render on updates.
451
+
452
+ useTrackedState will unwrap a Proxy before wrapping with a new Proxy,
453
+ hence, it will work fine in usual use cases.
454
+ There's only one known pitfall: If you wrap proxied state with your own Proxy
455
+ outside the control of useTrackedState,
456
+ it might lead memory leaks, because useTrackedState
457
+ wouldn't know how to unwrap your own Proxy.
458
+
459
+ To work around such edge cases, use primitive values.
431
460
432
461
` ` ` js
433
462
const state = useTrackedState ();
434
463
const dispatch = useUpdate ();
435
- dispatch ({ type: ' FOO' , value: state .foo }); // This may lead unexpected behavior if state.foo is an object
436
- dispatch ({ type: ' FOO' , value: state .fooStr }); // This is OK if state.fooStr is a string
464
+ dispatch ({ type: ' FOO' , value: state .fooObj }); // Instead of using objects,
465
+ dispatch ({ type: ' FOO' , value: state .fooStr }); // Use primitives.
437
466
` ` `
438
467
439
- It's recommended to use primitive values for ` dispatch` , ` setState` and others.
440
-
441
468
#### Performance
442
469
443
470
useSelector is sometimes more performant because Proxies are overhead.
@@ -446,7 +473,7 @@ useTrackedState is sometimes more performant because it doesn't need to invoke a
446
473
447
474
### What are the limitations in browser support?
448
475
449
- Proxies are not supported in old browsers like IE11, and React Native (JavaScript Core) .
476
+ Proxies are not supported in old browsers like IE11.
450
477
451
478
However, one could use [proxy-polyfill](https://github.com/GoogleChrome/proxy-polyfill) with care.
452
479
0 commit comments