no-did-update-set-state
no-did-update-set-state rule
Keywords: React, componentDidUpdate, setState, infinite loop, lifecycle, ESLint rule, LLM-optimized
Prevent calling setState in componentDidUpdate without a conditional. This rule is part of eslint-plugin-react-features.
Quick Summary
| Aspect | Details |
|---|---|
| Severity | Error (correctness) |
| Auto-Fix | ❌ No (requires conditional logic) |
| Category | React |
| ESLint MCP | ✅ Optimized for ESLint MCP integration |
| Best For | React class components |
Rule Details
Calling setState unconditionally in componentDidUpdate creates an infinite render loop. Always wrap setState calls in a condition that compares previous and current props/state.
Why This Matters
| Issue | Impact | Solution |
|---|---|---|
| 🔄 Infinite loop | Application crash | Add conditional check |
| 🐛 Performance | Excessive re-renders | Compare prev/current values |
| 🔍 Memory leak | Growing call stack | Proper update conditions |
Examples
❌ Incorrect
class UserProfile extends React.Component {
componentDidUpdate() {
// BAD: Unconditional setState causes infinite loop!
this.setState({ updated: true });
}
componentDidUpdate(prevProps) {
// BAD: No condition check
this.setState({ user: this.props.userId });
}
}✅ Correct
class UserProfile extends React.Component {
componentDidUpdate(prevProps, prevState) {
// GOOD: Conditional check prevents infinite loop
if (prevProps.userId !== this.props.userId) {
this.setState({ user: null, loading: true });
this.fetchUser(this.props.userId);
}
// GOOD: Check state changes too
if (prevState.count !== this.state.count) {
this.updateAnalytics(this.state.count);
}
}
}
// Better: Use functional components with hooks
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]); // Dependency array handles the condition
}Options
| Option | Type | Default | Description |
|---|---|---|---|
allowInCallback | boolean | false | Allow setState inside async callbacks |
Configuration with Options
{
rules: {
'react-features/no-did-update-set-state': ['error', {
allowInCallback: true
}]
}
}Configuration Examples
Basic Usage
{
rules: {
'react-features/no-did-update-set-state': 'error'
}
}Related Rules
no-did-mount-set-state- Similar for componentDidMountreact-class-to-hooks- Migrate to hooks
Further Reading
- componentDidUpdate - React docs
- Infinite Loop Prevention - Effect patterns
Known False Negatives
The following patterns are not detected due to static analysis limitations:
Dynamic Variable References
Why: Static analysis cannot trace values stored in variables or passed through function parameters.
// ❌ NOT DETECTED - Prop from variable
const propValue = computedValue;
<Component prop={propValue} /> // Computation not analyzedMitigation: Implement runtime validation and review code manually. Consider using TypeScript branded types for validated inputs.
Wrapped or Aliased Functions
Why: Custom wrapper functions or aliased methods are not recognized by the rule.
// ❌ NOT DETECTED - Custom wrapper
function myWrapper(data) {
return internalApi(data); // Wrapper not analyzed
}
myWrapper(unsafeInput);Mitigation: Apply this rule's principles to wrapper function implementations. Avoid aliasing security-sensitive functions.
Imported Values
Why: When values come from imports, the rule cannot analyze their origin or construction.
// ❌ NOT DETECTED - Value from import
import { getValue } from './helpers';
processValue(getValue()); // Cross-file not trackedMitigation: Ensure imported values follow the same constraints. Use TypeScript for type safety.