Skip to content

Commit b2a3869

Browse files
committed
[eslint] Add an option to require dependencies on effect hooks (#33344)
Summary: To prepare for automatic effect dependencies, some codebases may want to codemod existing useEffect calls with no deps to include an explicit undefined second argument in order to preserve the "run on every render" behavior. In sufficiently large codebases, this may require a temporary enforcement period where all effects provide an explicit dependencies argument. Outside of migration, relying on a component to render can lead to real bugs, especially when working with memoization. DiffTrain build for [99efc62](99efc62)
1 parent b31f950 commit b2a3869

35 files changed

+98
-86
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ const rule$2 = {
5656
type: 'string',
5757
},
5858
},
59+
requireExplicitEffectDeps: {
60+
type: 'boolean',
61+
}
5962
},
6063
},
6164
],
@@ -71,10 +74,12 @@ const rule$2 = {
7174
const experimental_autoDependenciesHooks = rawOptions && Array.isArray(rawOptions.experimental_autoDependenciesHooks)
7275
? rawOptions.experimental_autoDependenciesHooks
7376
: [];
77+
const requireExplicitEffectDeps = rawOptions && rawOptions.requireExplicitEffectDeps || false;
7478
const options = {
7579
additionalHooks,
7680
experimental_autoDependenciesHooks,
7781
enableDangerousAutofixThisMayCauseInfiniteLoops,
82+
requireExplicitEffectDeps,
7883
};
7984
function reportProblem(problem) {
8085
if (enableDangerousAutofixThisMayCauseInfiniteLoops) {
@@ -934,6 +939,13 @@ const rule$2 = {
934939
});
935940
return;
936941
}
942+
if (!maybeNode && isEffect && options.requireExplicitEffectDeps) {
943+
reportProblem({
944+
node: reactiveHook,
945+
message: `React Hook ${reactiveHookName} always requires dependencies. ` +
946+
`Please add a dependency array or an explicit \`undefined\``
947+
});
948+
}
937949
const isAutoDepsHook = options.experimental_autoDependenciesHooks.includes(reactiveHookName);
938950
if ((!declaredDependenciesNode ||
939951
(isAutoDepsHook &&

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
bfaeb4a46175fa0f4edf2eba58349d5029e5e86e
1+
99efc627a5a8cb56f50cfffee544c86c49572b6f
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
bfaeb4a46175fa0f4edf2eba58349d5029e5e86e
1+
99efc627a5a8cb56f50cfffee544c86c49572b6f

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1537,7 +1537,7 @@ __DEV__ &&
15371537
exports.useTransition = function () {
15381538
return resolveDispatcher().useTransition();
15391539
};
1540-
exports.version = "19.2.0-www-classic-bfaeb4a4-20250522";
1540+
exports.version = "19.2.0-www-classic-99efc627-20250523";
15411541
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
15421542
"function" ===
15431543
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
@@ -1537,7 +1537,7 @@ __DEV__ &&
15371537
exports.useTransition = function () {
15381538
return resolveDispatcher().useTransition();
15391539
};
1540-
exports.version = "19.2.0-www-modern-bfaeb4a4-20250522";
1540+
exports.version = "19.2.0-www-modern-99efc627-20250523";
15411541
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
15421542
"function" ===
15431543
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
@@ -635,4 +635,4 @@ exports.useSyncExternalStore = function (
635635
exports.useTransition = function () {
636636
return ReactSharedInternals.H.useTransition();
637637
};
638-
exports.version = "19.2.0-www-classic-bfaeb4a4-20250522";
638+
exports.version = "19.2.0-www-classic-99efc627-20250523";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -635,4 +635,4 @@ exports.useSyncExternalStore = function (
635635
exports.useTransition = function () {
636636
return ReactSharedInternals.H.useTransition();
637637
};
638-
exports.version = "19.2.0-www-modern-bfaeb4a4-20250522";
638+
exports.version = "19.2.0-www-modern-99efc627-20250523";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ exports.useSyncExternalStore = function (
639639
exports.useTransition = function () {
640640
return ReactSharedInternals.H.useTransition();
641641
};
642-
exports.version = "19.2.0-www-classic-bfaeb4a4-20250522";
642+
exports.version = "19.2.0-www-classic-99efc627-20250523";
643643
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
644644
"function" ===
645645
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
@@ -639,7 +639,7 @@ exports.useSyncExternalStore = function (
639639
exports.useTransition = function () {
640640
return ReactSharedInternals.H.useTransition();
641641
};
642-
exports.version = "19.2.0-www-modern-bfaeb4a4-20250522";
642+
exports.version = "19.2.0-www-modern-99efc627-20250523";
643643
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
644644
"function" ===
645645
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
@@ -19080,10 +19080,10 @@ __DEV__ &&
1908019080
(function () {
1908119081
var internals = {
1908219082
bundleType: 1,
19083-
version: "19.2.0-www-classic-bfaeb4a4-20250522",
19083+
version: "19.2.0-www-classic-99efc627-20250523",
1908419084
rendererPackageName: "react-art",
1908519085
currentDispatcherRef: ReactSharedInternals,
19086-
reconcilerVersion: "19.2.0-www-classic-bfaeb4a4-20250522"
19086+
reconcilerVersion: "19.2.0-www-classic-99efc627-20250523"
1908719087
};
1908819088
internals.overrideHookState = overrideHookState;
1908919089
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -19117,7 +19117,7 @@ __DEV__ &&
1911719117
exports.Shape = Shape;
1911819118
exports.Surface = Surface;
1911919119
exports.Text = Text;
19120-
exports.version = "19.2.0-www-classic-bfaeb4a4-20250522";
19120+
exports.version = "19.2.0-www-classic-99efc627-20250523";
1912119121
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1912219122
"function" ===
1912319123
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)