Skip to content

Commit 5ed5040

Browse files
committed
Add section about values and arguments to Hooks being immutable
1 parent a4f0530 commit 5ed5040

File tree

1 file changed

+62
-1
lines changed

1 file changed

+62
-1
lines changed

src/content/reference/rules/components-and-hooks-must-be-pure.md

+62-1
Original file line numberDiff line numberDiff line change
@@ -171,4 +171,65 @@ function Counter() {
171171
</button>
172172
);
173173
}
174-
```
174+
```
175+
176+
## Return values and arguments to Hooks are immutable {/*return-values-and-arguments-to-hooks-are-immutable*/}
177+
178+
Once values are passed to a Hook, neither the calling code nor the Hook should
179+
modify them. Like props in JSX, values become immutable when passed to a Hook.
180+
181+
```js {4}
182+
function useIconStyle(icon) {
183+
const theme = useContext(ThemeContext);
184+
if (icon.enabled) {
185+
// ❌ never mutate hook arguments directly
186+
icon.className = computeStyle(icon, theme);
187+
}
188+
return icon;
189+
}
190+
```
191+
192+
```js {4}
193+
function useIconStyle(icon) {
194+
const theme = useContext(ThemeContext);
195+
// ✅ make a copy instead
196+
let newIcon = { ...icon };
197+
if (icon.enabled) {
198+
newIcon.className = computeStyle(icon, theme);
199+
}
200+
return newIcon;
201+
}
202+
```
203+
204+
The custom Hook might have used the hook arguments as dependencies to memoize
205+
values inside it.
206+
207+
```js {4}
208+
function useIconStyle(icon) {
209+
const theme = useContext(ThemeContext);
210+
211+
return useMemo(() => {
212+
let newIcon = { ...icon };
213+
if (icon.enabled) {
214+
newIcon.className = computeStyle(icon, theme);
215+
}
216+
return newIcon;
217+
}, [icon, theme]);
218+
}
219+
```
220+
221+
Modifying the hook arguments after the hook call can cause issues, so it's important to avoid doing that.
222+
223+
```js {4}
224+
style = useIconStyle(icon); // `style` is memoized based on `icon`
225+
icon.enabled = false; // ❌ never mutate hook arguments directly
226+
style = useIconStyle(icon); // previously memoized result is returned
227+
```
228+
229+
```js {4}
230+
style = useIconStyle(icon); // `style` is memoized based on `icon`
231+
icon = { ...icon, enabled: false }; // ✅ make a copy instead
232+
style = useIconStyle(icon); // new value of `style` is calculated
233+
```
234+
235+
Similarly, it's important to not modify the return values of hooks, as they have been memoized.

0 commit comments

Comments
 (0)