From 9eed07a1e640d711f8ec3c8ce86d3c879fe0c00e Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Fri, 13 Nov 2026 20:45:03 +0530 Subject: [PATCH] Clarify that immutability lint does not report method-call mutations on state The immutability rule page listed items.push(), items.sort() and the todos.push() troubleshooting example as violations the rule catches. The compiler does not infer the types of state values, so it only reports mutations it can prove (such as property assignment) and produces no diagnostic for these method calls. Keep the property assignment as the invalid example, add a note that method-call mutations on state are not detected yet, and show a non-mutating sort in the valid examples. --- .../lints/immutability.md | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/content/reference/eslint-plugin-react-hooks/lints/immutability.md b/src/content/reference/eslint-plugin-react-hooks/lints/immutability.md index 2314cde0649..04829709f50 100644 --- a/src/content/reference/eslint-plugin-react-hooks/lints/immutability.md +++ b/src/content/reference/eslint-plugin-react-hooks/lints/immutability.md @@ -17,16 +17,6 @@ A component’s props and state are immutable snapshots. Never mutate them direc ### Invalid {/*invalid*/} ```js -// ❌ Array push mutation -function Component() { - const [items, setItems] = useState([1, 2, 3]); - - const addItem = () => { - items.push(4); // Mutating! - setItems(items); // Same reference, no re-render - }; -} - // ❌ Object property assignment function Component() { const [user, setUser] = useState({name: 'Alice'}); @@ -36,16 +26,13 @@ function Component() { setUser(user); // Same reference }; } +``` -// ❌ Sort without spreading -function Component() { - const [items, setItems] = useState([3, 1, 2]); + - const sortItems = () => { - setItems(items.sort()); // sort mutates! - }; -} -``` +The rule reports mutations it can prove, such as assigning to a property of a value from props or state. It does not infer the types of state values, so it cannot tell that a method call like `items.push(4)` or `items.sort()` mutates an array, and it does not report those calls yet. They still mutate state and are bugs, so create a new array instead, as shown below. + + ### Valid {/*valid*/} @@ -59,6 +46,15 @@ function Component() { }; } +// ✅ Sort a copy +function Component() { + const [items, setItems] = useState([3, 1, 2]); + + const sortItems = () => { + setItems([...items].sort()); // Sorts the copy, not the state + }; +} + // ✅ Create new object function Component() { const [user, setUser] = useState({name: 'Alice'}); @@ -73,7 +69,7 @@ function Component() { ### I need to add items to an array {/*add-items-array*/} -Mutating arrays with methods like `push()` won't trigger re-renders: +Mutating arrays with methods like `push()` won't trigger re-renders. The linter doesn't currently report these method calls on state, so you need to catch them yourself: ```js // ❌ Wrong: Mutating the array