no-direct-mutation-state
Disallows direct mutation of 'this.state'.
Full Name in eslint-plugin-react-x
react-x/no-direct-mutation-stateFull Name in @eslint-react/eslint-plugin
@eslint-react/no-direct-mutation-statePresets
x
recommended
recommended-typescript
recommended-type-checked
strict
strict-typescript
strict-type-checked
Rule Details
Never mutate this.state directly, as calling setState() afterward may replace the mutation you made. Treat this.state as if it were immutable.
The only place it's acceptable to assign this.state is in a class component's constructor.
Examples
Mutating this.state directly in an event handler
Mutating this.state directly does not trigger a re-render, and a subsequent setState may overwrite the change.
import React from "react";
interface MyComponentProps {}
interface MyComponentState {
foo: string;
}
// Problem: Assigning to this.state directly
class MyComponent extends React.Component<MyComponentProps, MyComponentState> {
state = {
foo: "bar",
};
render() {
return (
<div
onClick={() => {
this.state.foo = "baz";
// ^^^ Do not mutate state directly. Use 'setState()' instead.
}}
>
{this.state.foo}
</div>
);
}
}import React from "react";
interface MyComponentProps {}
interface MyComponentState {
foo: string;
}
// Recommended: Update state via setState
class MyComponent extends React.Component<MyComponentProps, MyComponentState> {
state = {
foo: "bar",
};
render() {
return (
<div
onClick={() => {
this.setState({ foo: "baz" });
}}
>
{this.state.foo}
</div>
);
}
}Mutating state in function components
Directly mutating a state object or array in a function component does not trigger a re-render and breaks React's state management.
// Problem: Mutating a state object directly instead of using the setter
import { useState } from "react";
function UserProfile() {
const [user, setUser] = useState({ name: "Taylor", age: 25 });
function handleClick() {
user.age = user.age + 1; // Mutates state directly — won't re-render!
}
return (
<button onClick={handleClick}>
{user.name} is {user.age} years old
</button>
);
}// Recommended: Always use the setter function with a new object
import { useState } from "react";
function UserProfile() {
const [user, setUser] = useState({ name: "Taylor", age: 25 });
function handleClick() {
setUser({ ...user, age: user.age + 1 });
}
return (
<button onClick={handleClick}>
{user.name} is {user.age} years old
</button>
);
}Versions
Resources
Further Reading
See Also
react-x/no-access-state-in-setstate
Disallows accessingthis.stateinsidesetStatecalls.react-x/no-set-state-in-component-did-mount
Disallows callingthis.setStateincomponentDidMountoutside functions such as callbacks.