react-hooks/set-state-in-effect fires eight times. They are not all the same problem, and a blanket "fix all eight" would make some of them worse, so this is a triage rather than a task list.
The eight
Site
Shape
customer/VerifyEmail.tsx:33
setStatus('failed') when there is no token
cart/CartContext.tsx:31
setItems([]) when there is no customer
customer/FavoritesContext.tsx:38
setFavorites([]) when there is no customer
customer/CustomerAuthContext.tsx:36
same shape
App.tsx:167
setLoading(true) before a debounced fetch
cart/Cart.tsx:72
load-on-mount
admin/Categories.tsx:81
load-on-mount
admin/Tags.tsx:39
load-on-mount
They fall into three groups
Genuinely derived state, worth fixing.VerifyEmail is the clearest: whether the link is missing its token is known during render, from the URL. No request is needed to find that out, so routing it through an effect and a state update means the component renders once in a state that was never true. This is exactly the case React's "You Might Not Need an Effect" is about.
A reset that could be derived but is defensible. The three context providers all do the same thing — clear their collection when the customer becomes null. That is real synchronisation with an external system (the session), and the alternative shapes are not obviously better: deriving would mean every consumer handles "signed out" itself, and the key remount trick is more indirection than the problem deserves. Worth deciding deliberately and writing the decision down rather than leaving three identical warnings that each future reader re-investigates.
Legitimate, flagged conservatively. The load-on-mount cases and App.tsx's setLoading(true) are fetches with a pending flag. The rule cannot distinguish "synchronising with a server" from "computing something I already knew", and this is the former.
What this issue should produce
Not eight fixes. A decision per site: fix the ones that are derived, and for the ones that stay, either a targeted eslint-disable-next-line with the reason or — better — a note in the file saying why the effect is the right tool. Eight standing warnings that nobody can distinguish from each other is how a lint gate stops being read, which is the outcome #60 explicitly designed against.
Note the trap #60 already recorded: eslint-disable-next-line must be the last comment line before the code. A multi-line explanation above it silently breaks the directive, and ESLint then reports both the original error and an unused-disable warning.
Verification
No behaviour change is intended for the sites that stay. VerifyEmail has end-to-end coverage for both the missing-token and invalid-token paths, so that one is checkable; the context providers are covered by the auth and favorites specs.
Severity
Low. No defect is known to result from any of these. The value is in the codebase not carrying eight identical-looking warnings of which only some matter.
Found during a React best-practices review.
`react-hooks/set-state-in-effect` fires eight times. They are **not all the same problem**, and a blanket "fix all eight" would make some of them worse, so this is a triage rather than a task list.
## The eight
| Site | Shape |
| --- | --- |
| `customer/VerifyEmail.tsx:33` | `setStatus('failed')` when there is no token |
| `cart/CartContext.tsx:31` | `setItems([])` when there is no customer |
| `customer/FavoritesContext.tsx:38` | `setFavorites([])` when there is no customer |
| `customer/CustomerAuthContext.tsx:36` | same shape |
| `App.tsx:167` | `setLoading(true)` before a debounced fetch |
| `cart/Cart.tsx:72` | load-on-mount |
| `admin/Categories.tsx:81` | load-on-mount |
| `admin/Tags.tsx:39` | load-on-mount |
## They fall into three groups
**Genuinely derived state, worth fixing.** `VerifyEmail` is the clearest: whether the link is missing its token is known during render, from the URL. No request is needed to find that out, so routing it through an effect and a state update means the component renders once in a state that was never true. This is exactly the case React's "You Might Not Need an Effect" is about.
**A reset that could be derived but is defensible.** The three context providers all do the same thing — clear their collection when the customer becomes null. That is real synchronisation with an external system (the session), and the alternative shapes are not obviously better: deriving would mean every consumer handles "signed out" itself, and the `key` remount trick is more indirection than the problem deserves. Worth *deciding* deliberately and writing the decision down rather than leaving three identical warnings that each future reader re-investigates.
**Legitimate, flagged conservatively.** The load-on-mount cases and `App.tsx`'s `setLoading(true)` are fetches with a pending flag. The rule cannot distinguish "synchronising with a server" from "computing something I already knew", and this is the former.
## What this issue should produce
Not eight fixes. A decision per site: fix the ones that are derived, and for the ones that stay, either a targeted `eslint-disable-next-line` with the reason or — better — a note in the file saying why the effect is the right tool. Eight standing warnings that nobody can distinguish from each other is how a lint gate stops being read, which is the outcome #60 explicitly designed against.
Note the trap #60 already recorded: `eslint-disable-next-line` must be the **last** comment line before the code. A multi-line explanation above it silently breaks the directive, and ESLint then reports both the original error and an unused-disable warning.
## Verification
No behaviour change is intended for the sites that stay. `VerifyEmail` has end-to-end coverage for both the missing-token and invalid-token paths, so that one is checkable; the context providers are covered by the auth and favorites specs.
## Severity
Low. No defect is known to result from any of these. The value is in the codebase not carrying eight identical-looking warnings of which only some matter.
Found during a React best-practices review.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
react-hooks/set-state-in-effectfires eight times. They are not all the same problem, and a blanket "fix all eight" would make some of them worse, so this is a triage rather than a task list.The eight
customer/VerifyEmail.tsx:33setStatus('failed')when there is no tokencart/CartContext.tsx:31setItems([])when there is no customercustomer/FavoritesContext.tsx:38setFavorites([])when there is no customercustomer/CustomerAuthContext.tsx:36App.tsx:167setLoading(true)before a debounced fetchcart/Cart.tsx:72admin/Categories.tsx:81admin/Tags.tsx:39They fall into three groups
Genuinely derived state, worth fixing.
VerifyEmailis the clearest: whether the link is missing its token is known during render, from the URL. No request is needed to find that out, so routing it through an effect and a state update means the component renders once in a state that was never true. This is exactly the case React's "You Might Not Need an Effect" is about.A reset that could be derived but is defensible. The three context providers all do the same thing — clear their collection when the customer becomes null. That is real synchronisation with an external system (the session), and the alternative shapes are not obviously better: deriving would mean every consumer handles "signed out" itself, and the
keyremount trick is more indirection than the problem deserves. Worth deciding deliberately and writing the decision down rather than leaving three identical warnings that each future reader re-investigates.Legitimate, flagged conservatively. The load-on-mount cases and
App.tsx'ssetLoading(true)are fetches with a pending flag. The rule cannot distinguish "synchronising with a server" from "computing something I already knew", and this is the former.What this issue should produce
Not eight fixes. A decision per site: fix the ones that are derived, and for the ones that stay, either a targeted
eslint-disable-next-linewith the reason or — better — a note in the file saying why the effect is the right tool. Eight standing warnings that nobody can distinguish from each other is how a lint gate stops being read, which is the outcome #60 explicitly designed against.Note the trap #60 already recorded:
eslint-disable-next-linemust be the last comment line before the code. A multi-line explanation above it silently breaks the directive, and ESLint then reports both the original error and an unused-disable warning.Verification
No behaviour change is intended for the sites that stay.
VerifyEmailhas end-to-end coverage for both the missing-token and invalid-token paths, so that one is checkable; the context providers are covered by the auth and favorites specs.Severity
Low. No defect is known to result from any of these. The value is in the codebase not carrying eight identical-looking warnings of which only some matter.
Found during a React best-practices review.