Skip to content

Commit 1b0132c

Browse files
authored
Consider dispatch from useActionState stable (facebook#29665)
1 parent f38c22b commit 1b0132c

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js

+50-1
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,8 @@ const tests = {
607607
const [state4, dispatch2] = React.useReducer();
608608
const [state5, maybeSetState] = useFunnyState();
609609
const [state6, maybeDispatch] = useFunnyReducer();
610+
const [state9, dispatch5] = useActionState();
611+
const [state10, dispatch6] = React.useActionState();
610612
const [isPending1] = useTransition();
611613
const [isPending2, startTransition2] = useTransition();
612614
const [isPending3] = React.useTransition();
@@ -624,6 +626,8 @@ const tests = {
624626
setState2();
625627
dispatch1();
626628
dispatch2();
629+
dispatch5();
630+
dispatch6();
627631
startTransition1();
628632
startTransition2();
629633
startTransition3();
@@ -646,7 +650,7 @@ const tests = {
646650
maybeDispatch();
647651
}, [
648652
// Dynamic
649-
state1, state2, state3, state4, state5, state6,
653+
state1, state2, state3, state4, state5, state6, state9, state10,
650654
maybeRef1, maybeRef2,
651655
isPending2, isPending4,
652656
@@ -1494,6 +1498,51 @@ const tests = {
14941498
},
14951499
],
14961500
},
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+
},
14971546
{
14981547
code: normalizeIndent`
14991548
function MyComponent(props) {

packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ export default {
179179
// ^^^ true for this reference
180180
// const [state, dispatch] = useReducer() / React.useReducer()
181181
// ^^^ true for this reference
182+
// const [state, dispatch] = useActionState() / React.useActionState()
183+
// ^^^ true for this reference
182184
// const ref = useRef()
183185
// ^^^ true for this reference
184186
// const onStuff = useEffectEvent(() => {})
@@ -260,7 +262,11 @@ export default {
260262
}
261263
// useEffectEvent() return value is always unstable.
262264
return true;
263-
} else if (name === 'useState' || name === 'useReducer') {
265+
} else if (
266+
name === 'useState' ||
267+
name === 'useReducer' ||
268+
name === 'useActionState'
269+
) {
264270
// Only consider second value in initializing tuple stable.
265271
if (
266272
id.type === 'ArrayPattern' &&

0 commit comments

Comments
 (0)