Skip to content

Commit 31940cd

Browse files
committed
[compiler] Option to treat "set-" prefixed callees as setState functions (facebook#34505)
Calling setState functions during render can lead to extraneous renders or even infinite loops. We also have runtime detection for loops, but static detection is obviously even better. This PR adds an option to infer identifers as setState functions if both the following conditions are met: - The identifier is named starting with "set" - The identifier is used as the callee of a call expression By inferring values as SetState type, this allows our existing ValidateNoSetStateInRender rule to flag calls during render, disallowing examples like the following: ```js function Component({setParentState}) { setParentState(...); ^^^^^^^^^^^^^^ Error: Cannot call setState in render } ``` DiffTrain build for [7899729](facebook@7899729)
1 parent c706b43 commit 31940cd

35 files changed

+95
-87
lines changed

compiled/eslint-plugin-react-hooks/index.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32155,6 +32155,7 @@ const EnvironmentConfigSchema = zod.z.object({
3215532155
enableCustomTypeDefinitionForReanimated: zod.z.boolean().default(false),
3215632156
hookPattern: zod.z.string().nullable().default(null),
3215732157
enableTreatRefLikeIdentifiersAsRefs: zod.z.boolean().default(true),
32158+
enableTreatSetIdentifiersAsStateSetters: zod.z.boolean().default(false),
3215832159
lowerContextAccess: ExternalFunctionSchema.nullable().default(null),
3215932160
validateNoVoidUseMemo: zod.z.boolean().default(false),
3216032161
validateNoDynamicallyCreatedComponentsOrHooks: zod.z.boolean().default(false),
@@ -48008,9 +48009,16 @@ function* generateInstructionTypes(env, names, instr) {
4800848009
}
4800948010
case 'CallExpression': {
4801048011
const returnType = makeType();
48012+
let shapeId = null;
48013+
if (env.config.enableTreatSetIdentifiersAsStateSetters) {
48014+
const name = getName(names, value.callee.identifier.id);
48015+
if (name.startsWith('set')) {
48016+
shapeId = BuiltInSetStateId;
48017+
}
48018+
}
4801148019
yield equation(value.callee.identifier.type, {
4801248020
kind: 'Function',
48013-
shapeId: null,
48021+
shapeId,
4801448022
return: returnType,
4801548023
isConstructor: false,
4801648024
});

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
348a4e2d44fed940313d0657ee180083d12ffc04
1+
78997291302c42b788dafa4c12da246e44be2dda
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
348a4e2d44fed940313d0657ee180083d12ffc04
1+
78997291302c42b788dafa4c12da246e44be2dda

compiled/facebook-www/React-dev.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1419,7 +1419,7 @@ __DEV__ &&
14191419
exports.useTransition = function () {
14201420
return resolveDispatcher().useTransition();
14211421
};
1422-
exports.version = "19.2.0-www-classic-348a4e2d-20250915";
1422+
exports.version = "19.2.0-www-classic-78997291-20250916";
14231423
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
14241424
"function" ===
14251425
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-dev.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1419,7 +1419,7 @@ __DEV__ &&
14191419
exports.useTransition = function () {
14201420
return resolveDispatcher().useTransition();
14211421
};
1422-
exports.version = "19.2.0-www-modern-348a4e2d-20250915";
1422+
exports.version = "19.2.0-www-modern-78997291-20250916";
14231423
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
14241424
"function" ===
14251425
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-prod.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,4 +602,4 @@ exports.useSyncExternalStore = function (
602602
exports.useTransition = function () {
603603
return ReactSharedInternals.H.useTransition();
604604
};
605-
exports.version = "19.2.0-www-classic-348a4e2d-20250915";
605+
exports.version = "19.2.0-www-classic-78997291-20250916";

compiled/facebook-www/React-prod.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,4 +602,4 @@ exports.useSyncExternalStore = function (
602602
exports.useTransition = function () {
603603
return ReactSharedInternals.H.useTransition();
604604
};
605-
exports.version = "19.2.0-www-modern-348a4e2d-20250915";
605+
exports.version = "19.2.0-www-modern-78997291-20250916";

compiled/facebook-www/React-profiling.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ exports.useSyncExternalStore = function (
606606
exports.useTransition = function () {
607607
return ReactSharedInternals.H.useTransition();
608608
};
609-
exports.version = "19.2.0-www-classic-348a4e2d-20250915";
609+
exports.version = "19.2.0-www-classic-78997291-20250916";
610610
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
611611
"function" ===
612612
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-profiling.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ exports.useSyncExternalStore = function (
606606
exports.useTransition = function () {
607607
return ReactSharedInternals.H.useTransition();
608608
};
609-
exports.version = "19.2.0-www-modern-348a4e2d-20250915";
609+
exports.version = "19.2.0-www-modern-78997291-20250916";
610610
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
611611
"function" ===
612612
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/ReactART-dev.classic.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19765,10 +19765,10 @@ __DEV__ &&
1976519765
(function () {
1976619766
var internals = {
1976719767
bundleType: 1,
19768-
version: "19.2.0-www-classic-348a4e2d-20250915",
19768+
version: "19.2.0-www-classic-78997291-20250916",
1976919769
rendererPackageName: "react-art",
1977019770
currentDispatcherRef: ReactSharedInternals,
19771-
reconcilerVersion: "19.2.0-www-classic-348a4e2d-20250915"
19771+
reconcilerVersion: "19.2.0-www-classic-78997291-20250916"
1977219772
};
1977319773
internals.overrideHookState = overrideHookState;
1977419774
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -19802,7 +19802,7 @@ __DEV__ &&
1980219802
exports.Shape = Shape;
1980319803
exports.Surface = Surface;
1980419804
exports.Text = Text;
19805-
exports.version = "19.2.0-www-classic-348a4e2d-20250915";
19805+
exports.version = "19.2.0-www-classic-78997291-20250916";
1980619806
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1980719807
"function" ===
1980819808
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)