Skip to content

Commit ddcecbb

Browse files
Consider dispatch function from useActionState non-reactive (#29917)
Updated version of #29758 removing `useFormState` since that was the previous name for `useActionState`. --------- Co-authored-by: Hieu Do <hieudn.uh@gmail.com>
1 parent 107a2f8 commit ddcecbb

File tree

7 files changed

+129
-13
lines changed

7 files changed

+129
-13
lines changed

compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Effect, ValueKind, ValueReason } from "./HIR";
99
import {
1010
BUILTIN_SHAPES,
1111
BuiltInArrayId,
12+
BuiltInUseActionStateId,
1213
BuiltInUseEffectHookId,
1314
BuiltInUseInsertionEffectHookId,
1415
BuiltInUseLayoutEffectHookId,
@@ -266,6 +267,18 @@ const REACT_APIS: Array<[string, BuiltInType]> = [
266267
returnValueReason: ValueReason.State,
267268
}),
268269
],
270+
[
271+
"useActionState",
272+
addHook(DEFAULT_SHAPES, {
273+
positionalParams: [],
274+
restParam: Effect.Freeze,
275+
returnType: { kind: "Object", shapeId: BuiltInUseActionStateId },
276+
calleeEffect: Effect.Read,
277+
hookKind: "useActionState",
278+
returnValueKind: ValueKind.Frozen,
279+
returnValueReason: ValueReason.State,
280+
}),
281+
],
269282
[
270283
"useReducer",
271284
addHook(DEFAULT_SHAPES, {

compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,18 @@ export function isSetStateType(id: Identifier): boolean {
15431543
return id.type.kind === "Function" && id.type.shapeId === "BuiltInSetState";
15441544
}
15451545

1546+
export function isUseActionStateType(id: Identifier): boolean {
1547+
return (
1548+
id.type.kind === "Object" && id.type.shapeId === "BuiltInUseActionState"
1549+
);
1550+
}
1551+
1552+
export function isSetActionStateType(id: Identifier): boolean {
1553+
return (
1554+
id.type.kind === "Function" && id.type.shapeId === "BuiltInSetActionState"
1555+
);
1556+
}
1557+
15461558
export function isUseReducerType(id: Identifier): boolean {
15471559
return id.type.kind === "Function" && id.type.shapeId === "BuiltInUseReducer";
15481560
}
@@ -1551,6 +1563,10 @@ export function isDispatcherType(id: Identifier): boolean {
15511563
return id.type.kind === "Function" && id.type.shapeId === "BuiltInDispatch";
15521564
}
15531565

1566+
export function isStableType(id: Identifier): boolean {
1567+
return isSetStateType(id) || isSetActionStateType(id) || isDispatcherType(id);
1568+
}
1569+
15541570
export function isUseEffectHookType(id: Identifier): boolean {
15551571
return (
15561572
id.type.kind === "Function" && id.type.shapeId === "BuiltInUseEffectHook"

compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ function addShape(
118118
export type HookKind =
119119
| "useContext"
120120
| "useState"
121+
| "useActionState"
121122
| "useReducer"
122123
| "useRef"
123124
| "useEffect"
@@ -195,6 +196,8 @@ export const BuiltInJsxId = "BuiltInJsx";
195196
export const BuiltInObjectId = "BuiltInObject";
196197
export const BuiltInUseStateId = "BuiltInUseState";
197198
export const BuiltInSetStateId = "BuiltInSetState";
199+
export const BuiltInUseActionStateId = "BuiltInUseActionState";
200+
export const BuiltInSetActionStateId = "BuiltInSetActionState";
198201
export const BuiltInUseRefId = "BuiltInUseRefId";
199202
export const BuiltInRefValueId = "BuiltInRefValue";
200203
export const BuiltInMixedReadonlyId = "BuiltInMixedReadonly";
@@ -396,6 +399,25 @@ addObject(BUILTIN_SHAPES, BuiltInUseStateId, [
396399
],
397400
]);
398401

402+
addObject(BUILTIN_SHAPES, BuiltInUseActionStateId, [
403+
["0", { kind: "Poly" }],
404+
[
405+
"1",
406+
addFunction(
407+
BUILTIN_SHAPES,
408+
[],
409+
{
410+
positionalParams: [],
411+
restParam: Effect.Freeze,
412+
returnType: PRIMITIVE_TYPE,
413+
calleeEffect: Effect.Read,
414+
returnValueKind: ValueKind.Primitive,
415+
},
416+
BuiltInSetActionStateId
417+
),
418+
],
419+
]);
420+
399421
addObject(BUILTIN_SHAPES, BuiltInUseReducerId, [
400422
["0", { kind: "Poly" }],
401423
[

compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ import {
1515
Place,
1616
computePostDominatorTree,
1717
getHookKind,
18-
isDispatcherType,
19-
isSetStateType,
18+
isStableType,
2019
isUseOperator,
2120
} from "../HIR";
2221
import { PostDominator } from "../HIR/Dominator";
@@ -220,10 +219,7 @@ export function inferReactivePlaces(fn: HIRFunction): void {
220219

221220
if (hasReactiveInput) {
222221
for (const lvalue of eachInstructionLValue(instruction)) {
223-
if (
224-
isSetStateType(lvalue.identifier) ||
225-
isDispatcherType(lvalue.identifier)
226-
) {
222+
if (isStableType(lvalue.identifier)) {
227223
continue;
228224
}
229225
reactiveIdentifiers.markReactive(lvalue);

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonReactiveDependencies.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import {
1010
ReactiveFunction,
1111
ReactiveInstruction,
1212
ReactiveScopeBlock,
13-
isDispatcherType,
14-
isSetStateType,
13+
isStableType,
1514
} from "../HIR";
1615
import { eachPatternOperand } from "../HIR/visitors";
1716
import { collectReactiveIdentifiers } from "./CollectReactiveIdentifiers";
@@ -57,10 +56,7 @@ class Visitor extends ReactiveFunctionVisitor<ReactiveIdentifiers> {
5756
case "Destructure": {
5857
if (state.has(value.value.identifier.id)) {
5958
for (const lvalue of eachPatternOperand(value.lvalue.pattern)) {
60-
if (
61-
isSetStateType(lvalue.identifier) ||
62-
isDispatcherType(lvalue.identifier)
63-
) {
59+
if (isStableType(lvalue.identifier)) {
6460
continue;
6561
}
6662
state.add(lvalue.identifier.id);
@@ -75,7 +71,7 @@ class Visitor extends ReactiveFunctionVisitor<ReactiveIdentifiers> {
7571
if (
7672
lvalue !== null &&
7773
state.has(value.object.identifier.id) &&
78-
!isSetStateType(lvalue.identifier)
74+
!isStableType(lvalue.identifier)
7975
) {
8076
state.add(lvalue.identifier.id);
8177
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
2+
## Input
3+
4+
```javascript
5+
import { useActionState } from "react";
6+
7+
function Component() {
8+
const [actionState, dispatchAction] = useActionState();
9+
const onSubmitAction = () => {
10+
dispatchAction();
11+
};
12+
return <Foo onSubmitAction={onSubmitAction} />;
13+
}
14+
15+
function Foo() {}
16+
17+
export const FIXTURE_ENTRYPOINT = {
18+
fn: Component,
19+
params: [],
20+
};
21+
22+
```
23+
24+
## Code
25+
26+
```javascript
27+
import { c as _c } from "react/compiler-runtime";
28+
import { useActionState } from "react";
29+
30+
function Component() {
31+
const $ = _c(1);
32+
const [actionState, dispatchAction] = useActionState();
33+
let t0;
34+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
35+
const onSubmitAction = () => {
36+
dispatchAction();
37+
};
38+
39+
t0 = <Foo onSubmitAction={onSubmitAction} />;
40+
$[0] = t0;
41+
} else {
42+
t0 = $[0];
43+
}
44+
return t0;
45+
}
46+
47+
function Foo() {}
48+
49+
export const FIXTURE_ENTRYPOINT = {
50+
fn: Component,
51+
params: [],
52+
};
53+
54+
```
55+
56+
### Eval output
57+
(kind: ok)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { useActionState } from "react";
2+
3+
function Component() {
4+
const [actionState, dispatchAction] = useActionState();
5+
const onSubmitAction = () => {
6+
dispatchAction();
7+
};
8+
return <Foo onSubmitAction={onSubmitAction} />;
9+
}
10+
11+
function Foo() {}
12+
13+
export const FIXTURE_ENTRYPOINT = {
14+
fn: Component,
15+
params: [],
16+
};

0 commit comments

Comments
 (0)