Open-source project
nickjvandyke/eslint-plugin-react-you-might-not-need-an-effect avatar
nickjvandyke/eslint-plugin-react-you-might-not-need-an-effect

How eslint-plugin-react-you-might-not-need-an-effect Finds Redundant React Effects

🙅‍♂️ Catch unnecessary React effects for simpler, faster, safer code.

1,922 stars20 forksJavaScriptMIT

At a glance

What is it?
This ESLint and Oxlint plugin detects React effects that duplicate render logic, act as event handlers, or derive state from other state. It is intended for React codebases that want more specific guidance than a general state-update check.
Who is it for?
Adopt this plugin when a React team wants lint feedback focused on unnecessary effects, especially code with derived state, chained updates, or effects acting as event handlers. Do not adopt it as a complete React correctness policy, since the README says its analysis assumes correct effect dependencies and benefits from an additional floating-promise rule.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 29 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why This Plugin Exists Beyond set-state-in-effect

The plugin targets a specific React maintenance problem: effects used where ordinary rendering, event handling, or state updates would be clearer. It is aimed at React developers working with hooks, teams reviewing pull requests, and anyone learning the boundary between render logic and side effects. The README positions the plugin as complementary to React's own eslint-plugin-react-hooks/set-state-in-effect rule. That rule flags synchronous setState calls inside effects, but this project examines a wider set of effect patterns.

Its documented rules include no-derived-state, no-chain-state-updates, no-event-handler, no-adjust-state-on-prop-change, no-reset-all-state-on-prop-change, no-pass-live-state-to-parent, no-pass-data-to-parent, no-external-store-subscription, and no-initialize-state. The distinction is useful in code review. An effect can cause an update, but it may still be unnecessary because the value can be computed during render. It may also be triggered by a state change that represents an event, even though the actual work could run directly in the handler.

The project says each report includes a specific suggested alternative and a React documentation link. That makes the tool more than a binary warning. It is designed to explain what to change and why the effect pattern is suspect. The plugin does not claim that every effect is harmful. React effects remain appropriate for synchronizing with external systems, for example, but the repository examples focus on cases where the effect is being used as render logic or as a substitute for direct event handling.

The Analysis Behind no-derived-state

The clearest documented example stores a person's first and last name in state, then stores their concatenation in a third state value through useEffect. The effect runs when firstName or lastName changes and sets fullName. The README identifies this as derived state and recommends computing fullName directly during render.

The rule therefore addresses a common state shape that creates synchronization work. With separate fullName state, the component must keep three values aligned. If the effect is delayed or interrupted, the stored value can temporarily disagree with its inputs. Removing fullName as state leaves firstName and lastName as the source values and makes the combined value a render-time calculation.

The plugin's description also says it analyzes state, props, refs, and their upstream sources and context. That matters because an effect can look redundant in a short snippet while being harder to classify when a value arrives through several components or helper functions. The project's stated dependency awareness also considers when an effect runs, rather than treating every synchronous state update as identical. Those claims describe the analysis approach documented in the README, not a measured performance result.

The no-chain-state-updates rule applies the same reasoning to dependent state. In the Game example, round controls whether isGameOver becomes true inside an effect. The recommended alternative is to update related state together when the relevant event or transition occurs, rather than letting one state variable trigger a later update to another.

Effects Used as Event Handlers in React Code

The no-event-handler rule covers two separate cases. In the first, a Form component stores dataToSubmit in state and an effect watches that state. When dataToSubmit becomes truthy, the effect calls submitData. The README recommends invoking the submission logic directly when the event occurs. The effect is acting as an event dispatcher, while the actual event handler could perform the action with the current value.

The second example passes product and addToCart into ProductPage. An effect checks product.isInCart and calls showNotification with product.name. The documentation says to move code that uses product to the parent component. This is different from the first example. The suggested location changes because the component that owns the event or the cart transition may be the appropriate boundary for the notification logic.

This rule exposes an important React design issue. State can represent what happened in the past, while an effect responds to that history. If code only needs to run because a value changed, it may belong in the code that changes that value. That can remove an extra state-to-effect cycle, but it also requires the developer to identify the actual event source. The lint report is guidance, not permission to move code without checking ownership and lifecycle behavior.

The other prop-oriented rules extend the same analysis to state adjustment after prop changes, resetting all state, passing live state to a parent, passing data to a parent, subscribing to external stores, and initializing state. The README does not provide complete examples for every rule in the available text, so their exact edge cases should be checked against the repository tests before enabling the full preset.

Installing the Plugin with npm and Yarn

The README documents installation as a development dependency because ESLint plugins are part of the project's development tooling. With npm, install the package in an existing React project:

bash
npm install --save-dev eslint-plugin-react-you-might-not-need-an-effect

The Yarn equivalent is:

bash
yarn add -D eslint-plugin-react-you-might-not-need-an-effect

The next step is to add the plugin to an ESLint configuration. For a first use, enable only no-derived-state as a warning rather than turning on every rule. The flat configuration shown in the README uses the plugin import, registers it under the `reactYouMightNotNeedAnEffect` key, and sets the rule name exactly:

javascript
import reactYouMightNotNeedAnEffect from "eslint-plugin-react-you-might-not-need-an-effect";

export default [
  {
    plugins: {
      reactYouMightNotNeedAnEffect,
    },
    rules: {
      "reactYouMightNotNeedAnEffect/no-derived-state": "warn",
    },
  },
];

This enables one focused check for teams that want to review reports on existing pull requests before expanding the rule set. The README also documents `configs.recommended`, which enables every rule as a warning, and `configs.strict`, which enables every rule as an error.

Flat Config, Legacy Config, and Oxlint

The package supports modern flat configuration and the older `.eslintrc` format. Flat configuration can use the recommended or strict preset directly, or it can register the plugin and select individual rules. The README's full example also configures browser globals and JSX parser options through `languageOptions`.

For a legacy project, the documented extends values are `plugin:react-you-might-not-need-an-effect/legacy-recommended` for warnings and `plugin:react-you-might-not-need-an-effect/legacy-strict` for errors. A project can instead place the package name in `plugins` and configure `react-you-might-not-need-an-effect/no-derived-state` directly. The naming differs between the flat and legacy formats, so copying a rule key from one style into the other will not work.

The repository also documents Oxlint support through its JavaScript plugin support. The `.oxlintrc.json` example registers the package in `jsPlugins` and lists nine rules with the `warn` severity. Oxlint therefore provides a separate route from ESLint configuration, while the package's rule names remain recognizable.

The package declares ESLint `>=8.40.0` as a peer dependency and Node `>=14.0.0` in its engines field. Its package metadata also defines separate ESM import and CommonJS require exports. That metadata matters when integrating the plugin into a mixed-module tooling setup, although the README does not document a complete migration procedure.

Limits of Static React Effect Analysis

The plugin is useful for static review, but it does not replace understanding of a component's behavior. Its README recommends enabling `eslint-plugin-react-hooks/exhaustive-deps` because the plugin assumes effects receive correct dependencies. It also suggests `typescript-eslint/no-floating-promises`, which helps the plugin infer calls to asynchronous functions. Those companion rules matter because missing dependency information or an unresolved promise call can limit what a linter can infer.

The available documentation does not claim perfect detection or define a false-positive rate. It says the project focuses on unusual syntax and heuristics to keep signal and noise high, but that is a design intention, not a benchmark claim. The tests are described as extensive invalid and valid examples under `src/rules`, and those tests are the appropriate source for checking unusual component structures before relying on a report.

A genuine wrong-tool case is an application whose effect synchronizes with a browser or server-side external system. The documented rules focus on derivations, state chains, event simulation, prop changes, parent data flow, external store subscriptions, and initialization. A rule that sees an external synchronization effect may need a different interpretation than a pure state transformation. The linter can identify a pattern, but only the developer can confirm whether the effect is required by the external system's lifecycle.

Another limitation is rule scope. This package does not replace React's compiler, a runtime profiler, a complete hooks lint policy, or tests. It also does not document a way to automatically rewrite the code. Reports provide alternatives, but applying them still requires understanding event ownership, async boundaries, and the intended synchronization contract.

Releases, Licensing, and Upgrade Work

The repository is not archived. Its last push was on 2026-09-24. The recent release history includes v1.0.0 on 2026-05-31, v1.0.1 on 2026-06-15, and v1.0.2 on 2026-08-20. The package version in `package.json` is v1.0.2. This supports adopting the current package while still checking release notes and rule behavior when upgrading from an earlier configuration.

The package is licensed under MIT. The repository lists `LICENSE`, and the package metadata identifies MIT as the license. That is a permissive license, but organizations should still check how the dependency fits their own license inventory and distribution process.

Upgrade work depends on configuration style. A flat-config project can review `configs.recommended` and `configs.strict`, while an `.eslintrc` project uses the legacy preset names. Changes in rule detection or recommended severity can create new findings even when application code has not changed. Pinning the package version in the project's lockfile and reviewing the rule tests after an upgrade are concrete maintenance steps tied to this repository.

The repository's build and verification scripts are `tsdown`, `tsgo`, `eslint`, Mocha, Prettier, `publint`, and `attw`. These show the project's own maintenance tooling, but they do not establish how much upgrade work an adopting project will have. The first upgrade should inspect changed lint output and the repository's `CHANGELOG.md`.

Editorial conclusion

Adopt this plugin when a React team wants lint feedback focused on unnecessary effects, especially code with derived state, chained updates, or effects acting as event handlers. Do not adopt it as a complete React correctness policy, since the README says its analysis assumes correct effect dependencies and benefits from an additional floating-promise rule. Verify the first issue by checking whether the suggested render-time or event-time replacement preserves the component's intended behavior, then inspect every enabled rule before choosing the strict preset.

Frequently asked questions

How do I install eslint-plugin-react-you-might-not-need-an-effect?

The README documents `npm install --save-dev eslint-plugin-react-you-might-not-need-an-effect` or `yarn add -D eslint-plugin-react-you-might-not-need-an-effect`. Add the package to ESLint or Oxlint configuration after installation.

Does this plugin replace react-hooks/set-state-in-effect?

No. The README says React's `set-state-in-effect` rule flags synchronous `setState` calls inside effects, while this plugin covers a broader set of unnecessary effect patterns. It recommends using it alongside other React hook analysis.

Can eslint-plugin-react-you-might-not-need-an-effect run with Oxlint?

Yes. The README documents Oxlint support through JavaScript plugins and provides an `.oxlintrc.json` example using `jsPlugins` and the plugin's rule names.

Official sources

  1. License: MIT
  2. nickjvandyke/eslint-plugin-react-you-might-not-need-an-effect on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/nickjvandyke-eslint-plugin-react-you-might-not-need-an-effect.svg)](https://hysenlabs.com/projects/nickjvandyke-eslint-plugin-react-you-might-not-need-an-effect)

Was this useful?