eslint-plugin-react-hooks 7.1.0-canary-ec9cc003-20251208 → 7.1.0-canary-d763f313-20251210

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18164,7 +18164,9 @@ function getRuleForCategoryImpl(category) {
18164
18164
  category,
18165
18165
  severity: ErrorSeverity.Error,
18166
18166
  name: 'set-state-in-effect',
18167
- description: 'Validates against calling setState synchronously in an effect, which can lead to re-renders that degrade performance',
18167
+ description: 'Validates against calling setState synchronously in an effect. ' +
18168
+ 'This can indicate non-local derived data, a derived event pattern, or ' +
18169
+ 'improper external data synchronization.',
18168
18170
  preset: LintRulePreset.Recommended,
18169
18171
  };
18170
18172
  }
@@ -32270,6 +32272,7 @@ const EnvironmentConfigSchema = v4.z.object({
32270
32272
  validateNoVoidUseMemo: v4.z.boolean().default(true),
32271
32273
  validateNoDynamicallyCreatedComponentsOrHooks: v4.z.boolean().default(false),
32272
32274
  enableAllowSetStateFromRefsInEffects: v4.z.boolean().default(true),
32275
+ enableVerboseNoSetStateInEffect: v4.z.boolean().default(false),
32273
32276
  enableInferEventHandlers: v4.z.boolean().default(false),
32274
32277
  });
32275
32278
  class Environment {
@@ -51245,21 +51248,48 @@ function validateNoSetStateInEffects(fn, env) {
51245
51248
  if (arg !== undefined && arg.kind === 'Identifier') {
51246
51249
  const setState = setStateFunctions.get(arg.identifier.id);
51247
51250
  if (setState !== undefined) {
51248
- errors.pushDiagnostic(CompilerDiagnostic.create({
51249
- category: ErrorCategory.EffectSetState,
51250
- reason: 'Calling setState synchronously within an effect can trigger cascading renders',
51251
- description: 'Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. ' +
51252
- 'In general, the body of an effect should do one or both of the following:\n' +
51253
- '* Update external systems with the latest state from React.\n' +
51254
- '* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\n' +
51255
- 'Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. ' +
51256
- '(https://react.dev/learn/you-might-not-need-an-effect)',
51257
- suggestions: null,
51258
- }).withDetails({
51259
- kind: 'error',
51260
- loc: setState.loc,
51261
- message: 'Avoid calling setState() directly within an effect',
51262
- }));
51251
+ const enableVerbose = env.config.enableVerboseNoSetStateInEffect;
51252
+ if (enableVerbose) {
51253
+ errors.pushDiagnostic(CompilerDiagnostic.create({
51254
+ category: ErrorCategory.EffectSetState,
51255
+ reason: 'Calling setState synchronously within an effect can trigger cascading renders',
51256
+ description: 'Effects are intended to synchronize state between React and external systems. ' +
51257
+ 'Calling setState synchronously causes cascading renders that hurt performance.\n\n' +
51258
+ 'This pattern may indicate one of several issues:\n\n' +
51259
+ '**1. Non-local derived data**: If the value being set could be computed from props/state ' +
51260
+ 'but requires data from a parent component, consider restructuring state ownership so the ' +
51261
+ 'derivation can happen during render in the component that owns the relevant state.\n\n' +
51262
+ "**2. Derived event pattern**: If you're detecting when a prop changes (e.g., `isPlaying` " +
51263
+ 'transitioning from false to true), this often indicates the parent should provide an event ' +
51264
+ 'callback (like `onPlay`) instead of just the current state. Request access to the original event.\n\n' +
51265
+ "**3. Force update / external sync**: If you're forcing a re-render to sync with an external " +
51266
+ 'data source (mutable values outside React), use `useSyncExternalStore` to properly subscribe ' +
51267
+ 'to external state changes.\n\n' +
51268
+ 'See: https://react.dev/learn/you-might-not-need-an-effect',
51269
+ suggestions: null,
51270
+ }).withDetails({
51271
+ kind: 'error',
51272
+ loc: setState.loc,
51273
+ message: 'Avoid calling setState() directly within an effect',
51274
+ }));
51275
+ }
51276
+ else {
51277
+ errors.pushDiagnostic(CompilerDiagnostic.create({
51278
+ category: ErrorCategory.EffectSetState,
51279
+ reason: 'Calling setState synchronously within an effect can trigger cascading renders',
51280
+ description: 'Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. ' +
51281
+ 'In general, the body of an effect should do one or both of the following:\n' +
51282
+ '* Update external systems with the latest state from React.\n' +
51283
+ '* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\n' +
51284
+ 'Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. ' +
51285
+ '(https://react.dev/learn/you-might-not-need-an-effect)',
51286
+ suggestions: null,
51287
+ }).withDetails({
51288
+ kind: 'error',
51289
+ loc: setState.loc,
51290
+ message: 'Avoid calling setState() directly within an effect',
51291
+ }));
51292
+ }
51263
51293
  }
51264
51294
  }
51265
51295
  }
@@ -56278,6 +56308,8 @@ const COMPILER_OPTIONS = {
56278
56308
  validateNoCapitalizedCalls: [],
56279
56309
  validateHooksUsage: true,
56280
56310
  validateNoDerivedComputationsInEffects: true,
56311
+ enableUseKeyedState: true,
56312
+ enableVerboseNoSetStateInEffect: true,
56281
56313
  },
56282
56314
  };
56283
56315
  const FLOW_SUPPRESSION_REGEX = /\$FlowFixMe\[([^\]]*)\]/g;
@@ -18155,7 +18155,9 @@ function getRuleForCategoryImpl(category) {
18155
18155
  category,
18156
18156
  severity: ErrorSeverity.Error,
18157
18157
  name: 'set-state-in-effect',
18158
- description: 'Validates against calling setState synchronously in an effect, which can lead to re-renders that degrade performance',
18158
+ description: 'Validates against calling setState synchronously in an effect. ' +
18159
+ 'This can indicate non-local derived data, a derived event pattern, or ' +
18160
+ 'improper external data synchronization.',
18159
18161
  preset: LintRulePreset.Recommended,
18160
18162
  };
18161
18163
  }
@@ -32097,6 +32099,7 @@ const EnvironmentConfigSchema = v4.z.object({
32097
32099
  validateNoVoidUseMemo: v4.z.boolean().default(true),
32098
32100
  validateNoDynamicallyCreatedComponentsOrHooks: v4.z.boolean().default(false),
32099
32101
  enableAllowSetStateFromRefsInEffects: v4.z.boolean().default(true),
32102
+ enableVerboseNoSetStateInEffect: v4.z.boolean().default(false),
32100
32103
  enableInferEventHandlers: v4.z.boolean().default(false),
32101
32104
  });
32102
32105
  class Environment {
@@ -51072,21 +51075,48 @@ function validateNoSetStateInEffects(fn, env) {
51072
51075
  if (arg !== undefined && arg.kind === 'Identifier') {
51073
51076
  const setState = setStateFunctions.get(arg.identifier.id);
51074
51077
  if (setState !== undefined) {
51075
- errors.pushDiagnostic(CompilerDiagnostic.create({
51076
- category: ErrorCategory.EffectSetState,
51077
- reason: 'Calling setState synchronously within an effect can trigger cascading renders',
51078
- description: 'Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. ' +
51079
- 'In general, the body of an effect should do one or both of the following:\n' +
51080
- '* Update external systems with the latest state from React.\n' +
51081
- '* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\n' +
51082
- 'Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. ' +
51083
- '(https://react.dev/learn/you-might-not-need-an-effect)',
51084
- suggestions: null,
51085
- }).withDetails({
51086
- kind: 'error',
51087
- loc: setState.loc,
51088
- message: 'Avoid calling setState() directly within an effect',
51089
- }));
51078
+ const enableVerbose = env.config.enableVerboseNoSetStateInEffect;
51079
+ if (enableVerbose) {
51080
+ errors.pushDiagnostic(CompilerDiagnostic.create({
51081
+ category: ErrorCategory.EffectSetState,
51082
+ reason: 'Calling setState synchronously within an effect can trigger cascading renders',
51083
+ description: 'Effects are intended to synchronize state between React and external systems. ' +
51084
+ 'Calling setState synchronously causes cascading renders that hurt performance.\n\n' +
51085
+ 'This pattern may indicate one of several issues:\n\n' +
51086
+ '**1. Non-local derived data**: If the value being set could be computed from props/state ' +
51087
+ 'but requires data from a parent component, consider restructuring state ownership so the ' +
51088
+ 'derivation can happen during render in the component that owns the relevant state.\n\n' +
51089
+ "**2. Derived event pattern**: If you're detecting when a prop changes (e.g., `isPlaying` " +
51090
+ 'transitioning from false to true), this often indicates the parent should provide an event ' +
51091
+ 'callback (like `onPlay`) instead of just the current state. Request access to the original event.\n\n' +
51092
+ "**3. Force update / external sync**: If you're forcing a re-render to sync with an external " +
51093
+ 'data source (mutable values outside React), use `useSyncExternalStore` to properly subscribe ' +
51094
+ 'to external state changes.\n\n' +
51095
+ 'See: https://react.dev/learn/you-might-not-need-an-effect',
51096
+ suggestions: null,
51097
+ }).withDetails({
51098
+ kind: 'error',
51099
+ loc: setState.loc,
51100
+ message: 'Avoid calling setState() directly within an effect',
51101
+ }));
51102
+ }
51103
+ else {
51104
+ errors.pushDiagnostic(CompilerDiagnostic.create({
51105
+ category: ErrorCategory.EffectSetState,
51106
+ reason: 'Calling setState synchronously within an effect can trigger cascading renders',
51107
+ description: 'Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. ' +
51108
+ 'In general, the body of an effect should do one or both of the following:\n' +
51109
+ '* Update external systems with the latest state from React.\n' +
51110
+ '* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\n' +
51111
+ 'Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. ' +
51112
+ '(https://react.dev/learn/you-might-not-need-an-effect)',
51113
+ suggestions: null,
51114
+ }).withDetails({
51115
+ kind: 'error',
51116
+ loc: setState.loc,
51117
+ message: 'Avoid calling setState() directly within an effect',
51118
+ }));
51119
+ }
51090
51120
  }
51091
51121
  }
51092
51122
  }
@@ -56105,6 +56135,8 @@ const COMPILER_OPTIONS = {
56105
56135
  validateNoCapitalizedCalls: [],
56106
56136
  validateHooksUsage: true,
56107
56137
  validateNoDerivedComputationsInEffects: true,
56138
+ enableUseKeyedState: true,
56139
+ enableVerboseNoSetStateInEffect: true,
56108
56140
  },
56109
56141
  };
56110
56142
  const FLOW_SUPPRESSION_REGEX = /\$FlowFixMe\[([^\]]*)\]/g;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-hooks",
3
3
  "description": "ESLint rules for React Hooks",
4
- "version": "7.1.0-canary-ec9cc003-20251208",
4
+ "version": "7.1.0-canary-d763f313-20251210",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/facebook/react.git",