Skip to content

Commit 34ecbfd

Browse files
committed
[lint] Enable custom hooks configuration for useEffectEvent calling rules (#34497)
We need to be able to specify additional effect hooks for the RulesOfHooks lint rule in order to allow useEffectEvent to be called by custom effects. ExhaustiveDeps does this with a regex suppplied to the rule, but that regex is not accessible from other rules. This diff introduces a `react-hooks` entry you can put in the eslint settings that allows you to specify custom effect hooks and share them across all rules. This works like: ``` { settings: { 'react-hooks': { additionalEffectHooks: string, }, }, } ``` The next diff allows useEffect to read from the same configuration. ---- --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34497). * #34637 * __->__ #34497 DiffTrain build for [92cfdc3](92cfdc3)
1 parent 5232899 commit 34ecbfd

35 files changed

+123
-89
lines changed

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

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57291,6 +57291,17 @@ function requireCodePathAnalyzer() {
5729157291
var codePathAnalyzerExports = requireCodePathAnalyzer();
5729257292
var CodePathAnalyzer = /*@__PURE__*/getDefaultExportFromCjs(codePathAnalyzerExports);
5729357293

57294+
const SETTINGS_KEY = 'react-hooks';
57295+
const SETTINGS_ADDITIONAL_EFFECT_HOOKS_KEY = 'additionalEffectHooks';
57296+
function getAdditionalEffectHooksFromSettings(settings) {
57297+
var _a;
57298+
const additionalHooks = (_a = settings[SETTINGS_KEY]) === null || _a === void 0 ? void 0 : _a[SETTINGS_ADDITIONAL_EFFECT_HOOKS_KEY];
57299+
if (additionalHooks != null && typeof additionalHooks === 'string') {
57300+
return new RegExp(additionalHooks);
57301+
}
57302+
return undefined;
57303+
}
57304+
5729457305
function isHookName(s) {
5729557306
return s === 'use' || /^use[A-Z0-9]/.test(s);
5729657307
}
@@ -57375,8 +57386,18 @@ function getNodeWithoutReactNamespace(node) {
5737557386
}
5737657387
return node;
5737757388
}
57378-
function isEffectIdentifier(node) {
57379-
return node.type === 'Identifier' && (node.name === 'useEffect' || node.name === 'useLayoutEffect' || node.name === 'useInsertionEffect');
57389+
function isEffectIdentifier(node, additionalHooks) {
57390+
const isBuiltInEffect = node.type === 'Identifier' &&
57391+
(node.name === 'useEffect' ||
57392+
node.name === 'useLayoutEffect' ||
57393+
node.name === 'useInsertionEffect');
57394+
if (isBuiltInEffect) {
57395+
return true;
57396+
}
57397+
if (additionalHooks && node.type === 'Identifier') {
57398+
return additionalHooks.test(node.name);
57399+
}
57400+
return false;
5738057401
}
5738157402
function isUseEffectEventIdentifier(node) {
5738257403
{
@@ -57394,8 +57415,21 @@ const rule = {
5739457415
recommended: true,
5739557416
url: 'https://react.dev/reference/rules/rules-of-hooks',
5739657417
},
57418+
schema: [
57419+
{
57420+
type: 'object',
57421+
additionalProperties: false,
57422+
properties: {
57423+
additionalHooks: {
57424+
type: 'string',
57425+
},
57426+
},
57427+
},
57428+
],
5739757429
},
5739857430
create(context) {
57431+
const settings = context.settings || {};
57432+
const additionalEffectHooks = getAdditionalEffectHooksFromSettings(settings);
5739957433
let lastEffect = null;
5740057434
const codePathReactHooksMapStack = [];
5740157435
const codePathSegmentStack = [];
@@ -57676,7 +57710,7 @@ const rule = {
5767657710
reactHooks.push(node.callee);
5767757711
}
5767857712
const nodeWithoutNamespace = getNodeWithoutReactNamespace(node.callee);
57679-
if ((isEffectIdentifier(nodeWithoutNamespace) ||
57713+
if ((isEffectIdentifier(nodeWithoutNamespace, additionalEffectHooks) ||
5768057714
isUseEffectEventIdentifier(nodeWithoutNamespace)) &&
5768157715
node.arguments.length > 0) {
5768257716
lastEffect = node;

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
063394cf821e5082e834c72ffb9cf6f8575c9b34
1+
92cfdc3a4ed8f3350b746bd79d87f6549db8003c
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
063394cf821e5082e834c72ffb9cf6f8575c9b34
1+
92cfdc3a4ed8f3350b746bd79d87f6549db8003c

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1458,7 +1458,7 @@ __DEV__ &&
14581458
exports.useTransition = function () {
14591459
return resolveDispatcher().useTransition();
14601460
};
1461-
exports.version = "19.2.0-www-classic-063394cf-20250930";
1461+
exports.version = "19.2.0-www-classic-92cfdc3a-20250930";
14621462
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
14631463
"function" ===
14641464
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
@@ -1458,7 +1458,7 @@ __DEV__ &&
14581458
exports.useTransition = function () {
14591459
return resolveDispatcher().useTransition();
14601460
};
1461-
exports.version = "19.2.0-www-modern-063394cf-20250930";
1461+
exports.version = "19.2.0-www-modern-92cfdc3a-20250930";
14621462
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
14631463
"function" ===
14641464
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
@@ -604,4 +604,4 @@ exports.useSyncExternalStore = function (
604604
exports.useTransition = function () {
605605
return ReactSharedInternals.H.useTransition();
606606
};
607-
exports.version = "19.2.0-www-classic-063394cf-20250930";
607+
exports.version = "19.2.0-www-classic-92cfdc3a-20250930";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,4 +604,4 @@ exports.useSyncExternalStore = function (
604604
exports.useTransition = function () {
605605
return ReactSharedInternals.H.useTransition();
606606
};
607-
exports.version = "19.2.0-www-modern-063394cf-20250930";
607+
exports.version = "19.2.0-www-modern-92cfdc3a-20250930";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ exports.useSyncExternalStore = function (
608608
exports.useTransition = function () {
609609
return ReactSharedInternals.H.useTransition();
610610
};
611-
exports.version = "19.2.0-www-classic-063394cf-20250930";
611+
exports.version = "19.2.0-www-classic-92cfdc3a-20250930";
612612
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
613613
"function" ===
614614
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
@@ -608,7 +608,7 @@ exports.useSyncExternalStore = function (
608608
exports.useTransition = function () {
609609
return ReactSharedInternals.H.useTransition();
610610
};
611-
exports.version = "19.2.0-www-modern-063394cf-20250930";
611+
exports.version = "19.2.0-www-modern-92cfdc3a-20250930";
612612
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
613613
"function" ===
614614
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
@@ -20281,10 +20281,10 @@ __DEV__ &&
2028120281
(function () {
2028220282
var internals = {
2028320283
bundleType: 1,
20284-
version: "19.2.0-www-classic-063394cf-20250930",
20284+
version: "19.2.0-www-classic-92cfdc3a-20250930",
2028520285
rendererPackageName: "react-art",
2028620286
currentDispatcherRef: ReactSharedInternals,
20287-
reconcilerVersion: "19.2.0-www-classic-063394cf-20250930"
20287+
reconcilerVersion: "19.2.0-www-classic-92cfdc3a-20250930"
2028820288
};
2028920289
internals.overrideHookState = overrideHookState;
2029020290
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -20319,7 +20319,7 @@ __DEV__ &&
2031920319
exports.Shape = Shape;
2032020320
exports.Surface = Surface;
2032120321
exports.Text = Text;
20322-
exports.version = "19.2.0-www-classic-063394cf-20250930";
20322+
exports.version = "19.2.0-www-classic-92cfdc3a-20250930";
2032320323
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
2032420324
"function" ===
2032520325
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)