Fix useResourceEffect in Fizz (#31758)
We're seeing errors when testing useResourceEffect in SSR and it turns out we're missing the noop dispatcher function on Fizz. I tested a local build with this change and it resolved the late mutation errors in the e2e tests.
Jack Pope committed
Dec 13, 2024 at 11:26 UTC
17ca4b157fcba6c734583513353ba72376a7ba2d
2 files changed
+54
packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js
+48
@@ -27,6 +27,7 @@ let useRef;
27
let useImperativeHandle;
28
let useInsertionEffect;
29
let useLayoutEffect;
30
+let useResourceEffect;
31
let useDebugValue;
32
let forwardRef;
33
let yieldedValues;
@@ -51,6 +52,7 @@ function initModules() {
52
useImperativeHandle = React.useImperativeHandle;
53
useInsertionEffect = React.useInsertionEffect;
54
useLayoutEffect = React.useLayoutEffect;
55
+ useResourceEffect = React.experimental_useResourceEffect;
56
forwardRef = React.forwardRef;
57
58
yieldedValues = [];
@@ -653,6 +655,52 @@ describe('ReactDOMServerHooks', () => {
655
});
656
});
657
658
+ describe('useResourceEffect', () => {
659
+ gate(flags => {
660
+ if (flags.enableUseResourceEffectHook) {
661
+ const yields = [];
662
+ itRenders(
663
+ 'should ignore resource effects on the server',
664
+ async render => {
665
+ function Counter(props) {
666
+ useResourceEffect(
667
+ () => {
668
+ yieldValue('created on client');
669
+ return {resource_counter: props.count};
670
+ },
671
+ [props.count],
672
+ resource => {
673
+ resource.resource_counter = props.count;
674
+ yieldValue('updated on client');
675
+ },
676
+ [props.count],
677
+ () => {
678
+ yieldValue('cleanup on client');
679
+ },
680
+ );
681
+ return <Text text={'Count: ' + props.count} />;
682
+ }
683
+
684
+ const domNode = await render(<Counter count={0} />);
685
+ yields.push(clearLog());
686
+ expect(domNode.tagName).toEqual('SPAN');
687
+ expect(domNode.textContent).toEqual('Count: 0');
688
+ },
689
+ );
690
+
691
+ it('verifies yields in order', () => {
692
+ expect(yields).toEqual([
693
+ ['Count: 0'], // server render
694
+ ['Count: 0'], // server stream
695
+ ['Count: 0', 'created on client'], // clean render
696
+ ['Count: 0', 'created on client'], // hydrated render
697
+ // nothing yielded for bad markup
698
+ ]);
699
+ });
700
+ }
701
+ });
702
+ });
703
+
704
describe('useContext', () => {
705
itThrowsWhenRendering(
706
'if used inside a class component',
packages/react-server/src/ReactFizzHooks.js
+6
@@ -43,6 +43,7 @@ import {
43
enableUseEffectEventHook,
44
enableUseMemoCacheHook,
45
enableAsyncActions,
46
+ enableUseResourceEffectHook,
47
} from 'shared/ReactFeatureFlags';
48
import is from 'shared/objectIs';
49
import {
@@ -870,6 +871,11 @@ if (enableAsyncActions) {
871
HooksDispatcher.useFormState = useActionState;
872
HooksDispatcher.useActionState = useActionState;
873
}
874
+if (enableUseResourceEffectHook) {
875
+ HooksDispatcher.useResourceEffect = supportsClientAPIs
876
+ ? noop
877
+ : clientHookNotSupported;
878
+}
879
880
export let currentResumableState: null | ResumableState = (null: any);
881
export function setCurrentResumableState(