Consider dispatch from `useActionState` stable (#29665)
Sebastian Silbermann committed
Jul 6, 2024 at 08:52 UTC
1b0132c05acabae5aebd32c2cadddfb16bda70bc
2 files changed
+57
-2
packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js
+50
-1
@@ -607,6 +607,8 @@ const tests = {
607
const [state4, dispatch2] = React.useReducer();
608
const [state5, maybeSetState] = useFunnyState();
609
const [state6, maybeDispatch] = useFunnyReducer();
610
+ const [state9, dispatch5] = useActionState();
611
+ const [state10, dispatch6] = React.useActionState();
612
const [isPending1] = useTransition();
613
const [isPending2, startTransition2] = useTransition();
614
const [isPending3] = React.useTransition();
@@ -624,6 +626,8 @@ const tests = {
626
setState2();
627
dispatch1();
628
dispatch2();
629
+ dispatch5();
630
+ dispatch6();
631
startTransition1();
632
startTransition2();
633
startTransition3();
@@ -646,7 +650,7 @@ const tests = {
650
maybeDispatch();
651
}, [
652
// Dynamic
649
- state1, state2, state3, state4, state5, state6,
653
+ state1, state2, state3, state4, state5, state6, state9, state10,
654
maybeRef1, maybeRef2,
655
isPending2, isPending4,
656
@@ -1494,6 +1498,51 @@ const tests = {
1498
},
1499
],
1500
},
1501
+ {
1502
+ // Affected code should use React.useActionState instead
1503
+ code: normalizeIndent`
1504
+ function ComponentUsingFormState(props) {
1505
+ const [state7, dispatch3] = useFormState();
1506
+ const [state8, dispatch4] = ReactDOM.useFormState();
1507
+ useEffect(() => {
1508
+ dispatch3();
1509
+ dispatch4();
1510
+
1511
+ // dynamic
1512
+ console.log(state7);
1513
+ console.log(state8);
1514
+
1515
+ }, [state7, state8]);
1516
+ }
1517
+ `,
1518
+ errors: [
1519
+ {
1520
+ message:
1521
+ "React Hook useEffect has missing dependencies: 'dispatch3' and 'dispatch4'. " +
1522
+ 'Either include them or remove the dependency array.',
1523
+ suggestions: [
1524
+ {
1525
+ desc: 'Update the dependencies array to be: [dispatch3, dispatch4, state7, state8]',
1526
+ output: normalizeIndent`
1527
+ function ComponentUsingFormState(props) {
1528
+ const [state7, dispatch3] = useFormState();
1529
+ const [state8, dispatch4] = ReactDOM.useFormState();
1530
+ useEffect(() => {
1531
+ dispatch3();
1532
+ dispatch4();
1533
+
1534
+ // dynamic
1535
+ console.log(state7);
1536
+ console.log(state8);
1537
+
1538
+ }, [dispatch3, dispatch4, state7, state8]);
1539
+ }
1540
+ `,
1541
+ },
1542
+ ],
1543
+ },
1544
+ ],
1545
+ },
1546
{
1547
code: normalizeIndent`
1548
function MyComponent(props) {
packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
+7
-1
@@ -179,6 +179,8 @@ export default {
179
// ^^^ true for this reference
180
// const [state, dispatch] = useReducer() / React.useReducer()
181
// ^^^ true for this reference
182
+ // const [state, dispatch] = useActionState() / React.useActionState()
183
+ // ^^^ true for this reference
184
// const ref = useRef()
185
// ^^^ true for this reference
186
// const onStuff = useEffectEvent(() => {})
@@ -260,7 +262,11 @@ export default {
262
}
263
// useEffectEvent() return value is always unstable.
264
return true;
263
- } else if (name === 'useState' || name === 'useReducer') {
265
+ } else if (
266
+ name === 'useState' ||
267
+ name === 'useReducer' ||
268
+ name === 'useActionState'
269
+ ) {
270
// Only consider second value in initializing tuple stable.
271
if (
272
id.type === 'ArrayPattern' &&