react-doctor/no-cascading-set-state
Combine into useReducer: `const [state, dispatch] = useReducer(reducer, initialState)`
- Category: State & Effects
- Severity: warn
- Source:
oxlint-plugin-react-doctor - Framework: global
- Enabled when: always
Validation prompt
Use this to decide whether a fired diagnostic is real or a false positive.
Fires when 3 or more identifier calls matching /^set[A-Z]/ appear anywhere inside a useEffect or useLayoutEffect body — CASCADING_SET_STATE_THRESHOLD is 3. The walker recurses into nested callbacks, so setters inside .then() or setTimeout still count toward the total. False positive: identifiers that happen to start with set + uppercase but are not useState setters (setHours on a Date, element.style.setProperty), or genuinely independent updates that touch disparate state slices.
Fix prompt
Use this once validation confirms the diagnostic is real.
Combine the related fields into a single useReducer: const [state, dispatch] = useReducer(reducer, initialState), then dispatch ONE action whose reducer returns the next snapshot in a single immutable step. If some values are derivable from others, compute the derived ones during render instead of writing them to state. See https://react.dev/reference/react/useReducer
Related rules
More State & Effects rules from the rules reference:
react-doctor/no-derived-state-effect: For derived state, compute inline: `const x = fn(dep)`. For state resets on prop change, use a key prop: `<Component key={prop} />`. See https://react.dev/learn/you-might-not-need-an-effectreact-doctor/no-derived-use: Don't pass a promise created during render into use(); create it in a Server Component (or a stable cache) so its reference stays stable across rendersreact-doctor/no-derived-useState: Remove useState and compute the value inline: `const value = transform(propName)`react-doctor/no-did-mount-set-state: Derive state in getDerivedStateFromProps or initial state instead of calling this.setState in componentDidMount, which forces an extra render.react-doctor/no-did-update-set-state: Avoid calling this.setState in componentDidUpdate; derive the value with getDerivedStateFromProps to prevent re-render loops