You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/content/reference/rules/components-and-hooks-must-be-pure.md
+104-3
Original file line number
Diff line number
Diff line change
@@ -1,13 +1,50 @@
1
1
---
2
-
title: Side effects must run outside of render
2
+
title: Components and Hooks must be pure
3
3
---
4
4
5
5
<Intro>
6
-
Side effects should not run in render, as React can render components multiple times to create the best possible user experience.
6
+
TODO
7
7
</Intro>
8
8
9
+
<InlineToc />
10
+
9
11
---
10
12
13
+
## Components must be idempotent {/*components-must-be-idempotent*/}
14
+
15
+
React components are assumed to always return the same output with respect to their props. This is known as [idempotency](https://stackoverflow.com/questions/1077412/what-is-an-idempotent-operation).
16
+
17
+
Put simply, idempotence means that you [always get the same result everytime](learn/keeping-components-pure) you run that piece of code.
This means that _all_ code that runs during render must also be idempotent in order for this rule to hold. For example, this line of code is not idempotent (and therefore, neither is the component) and breaks this rule:
32
+
33
+
```js {2}
34
+
functionClock() {
35
+
constdate=newDate(); // ❌ always returns a different result!
36
+
return<div>{date}</div>
37
+
}
38
+
```
39
+
40
+
`newDate()` is not idempotent as it always returns the current date and changes its result every time it's called. When you render the above component, the time displayed on the screen will stay stuck on the time that the component was rendered. Similarly, functions like `Math.random()` also aren't idempotent, because they return different results every time they're called, even when the inputs are the same.
41
+
42
+
Try building a component that displays the time in real-time in our [challenge](learn/keeping-components-pure#challenges) to see if you follow this rule!
43
+
44
+
## Side effects must run outside of render {/*side-effects-must-run-outside-of-render*/}
45
+
46
+
Side effects should not run in render, as React can render components multiple times to create the best possible user experience.
47
+
11
48
While render must be kept pure, side effects are necessary at some point in order for your app to do anything interesting, like showing something on the screen! The key point of this rule is that side effects should not run in render, as React can render components multiple times. In most cases, you'll use [event handlers](learn/responding-to-events) to handle side effects.
12
49
13
50
For example, you might have an event handler that displays a confirmation dialog after the user clicks a button. Using an event handler explicitly tells React that this code doesn't need to run during render, keeping render pure. If you've exhausted all options – and only as a last resort – you can also handle side effects using `useEffect`.
@@ -21,7 +58,7 @@ When render is kept pure, React can understand how to prioritize which updates a
21
58
Concretely, this means that rendering logic can be run multiple times in a way that allows React to give your user a pleasant user experience. However, if your component has an untracked side effect – like modifying the value of a global variable during render – when React runs your rendering code again, your side effects will be triggered in a way that won't match what you want. This often leads to unexpected bugs that can degrade how your users experience your app.
22
59
</DeepDive>
23
60
24
-
## When is it okay to have mutation? {/*mutation*/}
61
+
### When is it okay to have mutation? {/*mutation*/}
25
62
One common example of a side effect is mutation, which refers to changing the value of a non-[primitive](https://developer.mozilla.org/en-US/docs/Glossary/Primitive) value. In general, while mutation is not idiomatic in React, _local_ mutation is absolutely fine:
26
63
27
64
```js {2}
@@ -71,3 +108,67 @@ function ProductDetailPage({ product }) {
71
108
```
72
109
73
110
As long as calling a component multiple times is safe and doesn’t affect the rendering of other components, React doesn’t care if it’s 100% pure in the strict functional programming sense of the word. It is more important that [components must be idempotent](/reference/rules/components-must-be-idempotent).
111
+
112
+
## Props and state are immutable {/*props-and-state-are-immutable*/}
113
+
114
+
A component's props and state are immutable [snapshots](learn/state-as-a-snapshot) with respect to a single render. Never mutate them directly.
115
+
116
+
You can think of the props and state values as snapshots that are updated after rendering. For this reason, you don't modify the props or state variables directly: instead you pass new props, or use the setter function provided to you to tell React that state needs to update the next time the component is rendered.
117
+
118
+
### Don't mutate Props {/*props*/}
119
+
When followed, this rule allows React to understand that values that flow from props aren't mutated when they're passed as arguments to functions, allowing certain optimizations to be made. Mutating props may also indicate a bug in your app – changing values on the props object doesn't cause the component to update, leaving your users with an outdated UI.
120
+
121
+
```js {2}
122
+
functionPost({ item }) {
123
+
item.url=newUrl(item.url, base); // ❌ never mutate props directly
124
+
return<Link url={item.url}>{item.title}</Link>;
125
+
}
126
+
```
127
+
128
+
```js {2}
129
+
functionPost({ item }) {
130
+
consturl=newUrl(item.url, base); // ✅ make a copy instead
131
+
return<Link url={url}>{item.title}</Link>;
132
+
}
133
+
```
134
+
135
+
### Don't mutate State {/*state*/}
136
+
`useState` returns the state variable and a setter to update that state.
137
+
138
+
```js
139
+
const [stateVariable, setter] =useState(0);
140
+
```
141
+
142
+
Rather than updating the state variable in-place, we need to update it using the setter function that is returned by `useState`. Changing values on the state variable doesn't cause the component to update, leaving your users with an outdated UI. Using the setter function informs React that the state has changed, and that we need to queue a re-render to update the UI.
143
+
144
+
```js {5}
145
+
functionCounter() {
146
+
const [count, setCount] =useState(0);
147
+
148
+
functionhandleClick() {
149
+
count = count +1; // ❌ never mutate state directly
150
+
}
151
+
152
+
return (
153
+
<button onClick={handleClick}>
154
+
You pressed me {count} times
155
+
</button>
156
+
);
157
+
}
158
+
```
159
+
160
+
```js {5}
161
+
functionCounter() {
162
+
const [count, setCount] =useState(0);
163
+
164
+
functionhandleClick() {
165
+
setCount(count +1); // ✅ use the setter function returned by useState
Copy file name to clipboardExpand all lines: src/content/reference/rules/index.md
+4-12
Original file line number
Diff line number
Diff line change
@@ -22,15 +22,7 @@ These rules have been used in the design of all of React's features over the yea
22
22
The Rules of React are proven rules used at companies like Meta that help you maintain an application and codebase that scales with you. When followed, your codebase becomes easier to understand and maintain, is less buggy, and helps React ensure your code runs efficiently by default.
23
23
</DeepDive>
24
24
25
-
---
26
-
27
-
## Rules {/*rules*/}
28
-
*[Side effects must run outside of render](/reference/rules/side-effects-must-run-outside-of-render): React can start and stop rendering components multiple times to create the best possible user experience.
29
-
*[Components must be idempotent](/reference/rules/components-must-be-idempotent): React components are assumed to always return the same output with respect to their props.
30
-
*[Props and state are immutable](/reference/rules/props-and-state-are-immutable): A component's props and state are immutable "snapshots" with respect to a single render.
31
-
*[Never call component functions directly](/reference/rules/never-call-component-functions-directly): Components should only be used in JSX. Don't call them as regular functions.
32
-
*[Never pass around Hooks as regular values](/reference/rules/never-pass-around-hooks-as-regular-values): Hooks should only be called inside of components. Never pass it around as a regular value.
33
-
*[Only call Hooks at the top level](/reference/rules/only-call-hooks-at-the-top-level): Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns.
34
-
*[Only call Hooks from React functions](/reference/rules/only-call-hooks-from-react-functions): Don’t call Hooks from regular JavaScript functions.
35
-
*[Values are immutable after being passed to JSX](/reference/rules/values-are-immutable-after-being-passed-to-jsx): Don't mutate values after they've been used in JSX. Move the mutation before the JSX is created.
36
-
*[Return values and arguments to Hooks are immutable](/reference/rules/return-values-and-arguments-to-hooks-are-immutable): TODO
25
+
*[Components and Hooks must be pure](/reference/rules/components-and-hooks-must-be-pure)
26
+
*[React orchestrates Components and Hooks](/reference/rules/react-orchestrates-components-and-hooks)
27
+
*[Rules of Hooks](/reference/rules/rules-of-hooks)
0 commit comments