Bugfix: useFormState queues actions in wrong order (#27570)
I neglected to update the "last" pointer of the action queue. Since the queue is circular, rather than dropping the update, the effect was to add the update to the front of the queue instead of the back. I didn't notice earlier because in my demos/tests, the actions would either resolve really quickly or the actions weren't order dependent (like incrementing a counter).
Andrew Clark committed
Oct 23, 2023 at 14:52 UTC
b8e47d988eb3ba547c102c0b12c351250ed955e0
2 files changed
+31
-2
packages/react-dom/src/__tests__/ReactDOMForm-test.js
+30
-1
@@ -90,7 +90,7 @@ describe('ReactDOMForm', () => {
90
const thenable = record.value;
91
record.status = 'resolved';
92
record.value = text;
93
- thenable.pings.forEach(t => t());
93
+ thenable.pings.forEach(t => t(text));
94
}
95
}
96
@@ -1082,6 +1082,35 @@ describe('ReactDOMForm', () => {
1082
});
1083
});
1084
1085
+ // @gate enableFormActions
1086
+ // @gate enableAsyncActions
1087
+ test('queues multiple actions and runs them in order', async () => {
1088
+ let action;
1089
+ function App() {
1090
+ const [state, dispatch] = useFormState(
1091
+ async (s, a) => await getText(a),
1092
+ 'A',
1093
+ );
1094
+ action = dispatch;
1095
+ return <Text text={state} />;
1096
+ }
1097
+
1098
+ const root = ReactDOMClient.createRoot(container);
1099
+ await act(() => root.render(<App />));
1100
+ assertLog(['A']);
1101
+
1102
+ await act(() => action('B'));
1103
+ await act(() => action('C'));
1104
+ await act(() => action('D'));
1105
+
1106
+ await act(() => resolveText('B'));
1107
+ await act(() => resolveText('C'));
1108
+ await act(() => resolveText('D'));
1109
+
1110
+ assertLog(['D']);
1111
+ expect(container.textContent).toBe('D');
1112
+ });
1113
+
1114
// @gate enableFormActions
1115
// @gate enableAsyncActions
1116
test('useFormState: warns if action is not async', async () => {
packages/react-reconciler/src/ReactFiberHooks.js
+1
-1
@@ -1915,7 +1915,7 @@ function dispatchFormState<S, P>(
1915
payload,
1916
next: first,
1917
};
1918
- last.next = newLast;
1918
+ actionQueue.pending = last.next = newLast;
1919
}
1920
}
1921