Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync with react.dev @ b7bf6c16 #357

Open
wants to merge 87 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
9ceb057
Revert "fix(sandpack): clear up bundler timeout when there's a syntax…
harish-sethuraman Feb 26, 2024
41b1bb3
Update Dan's twitter link
gaearon Feb 26, 2024
6d8e094
fix: Update @codesandbox/sandpack-react version to 2.13.4 (#6664)
danilowoz Feb 27, 2024
6e650f9
update: "Configuring TypeScript" link for Next.js App Directory - to …
tomihq Feb 29, 2024
6310c8a
Add /link redirects (#6670)
rickhanlonii Mar 1, 2024
265fa26
Update small typo in useDeferredValue.md (#6673)
ninjaPixel Mar 3, 2024
716e889
Add hydration-mismatch link (#6678)
rickhanlonii Mar 4, 2024
5de8519
fix: Update sandpack-react version to 2.13.5 (#6668)
danilowoz Mar 8, 2024
aa31fe5
Add details about shallow renderer warning (#6689)
jackpope Mar 11, 2024
1a839ff
Remove links to localhost (#6696)
poteto Mar 14, 2024
0dc1b31
Add initial Rules of React docs (#6680)
poteto Mar 15, 2024
f55d948
Reorder rules of react summary in reference index (#6698)
poteto Mar 15, 2024
ef3a7ea
Fix typos in typescript.md (#6439)
pavelsavva Mar 19, 2024
5a45b53
Fix hover styles in strictmode docs (#6705)
rickhanlonii Mar 23, 2024
9c04f9b
Correct pluralization of 'covers' (#6702)
allison-strandberg Mar 23, 2024
7bdbab1
Fix missing id properties in docs example (#6395)
jpayoung Mar 24, 2024
d661678
Update @eps1lon's job title (#6710)
poteto Mar 25, 2024
4df3124
Fix caps for React concepts (#6712)
rickhanlonii Mar 27, 2024
2aa9594
Add warning page for ReactDOMTestUtils deprecation (#6716)
eps1lon Mar 27, 2024
9b4de7c
Add Jack to team page (#6721)
rickhanlonii Mar 28, 2024
6436bd9
Fix typo in components-and-hooks-must-be-pure.md (#6724)
rivea0 Mar 29, 2024
3076795
chore: fix typos (#6723)
ahmoin Mar 29, 2024
9748943
Update Node.js version in engines into package.json file (^21.0.0) (#…
foridpathan Mar 31, 2024
712556c
Fix inconsistent link underline on hover (#6731)
poteto Apr 2, 2024
93177e6
fix(rules-of-react): "everytime" -> "every time" (#6737)
SiarheiBobryk Apr 6, 2024
a7103d8
Add Ruslan to team page (#6738)
rickhanlonii Apr 8, 2024
11a7479
Fixes #6693: fixes search functionality on iOS devices (#6743)
ramizackaryshamir Apr 10, 2024
342fddb
Revert inappropriate capitalization of "Transition" (#6746)
smikitky Apr 10, 2024
db2dc7f
Add docs for onCaughtError and onUncaughtError (#6742)
rickhanlonii Apr 11, 2024
2749eb4
Update link to nearestnabors.com (#6754)
jackpope Apr 15, 2024
56ca8f1
[easy] remove unused ref in ExpandableCallout.tsx (#6755)
kassens Apr 15, 2024
c2180a3
fix issue #6734 (#6735)
wheeler6123 Apr 17, 2024
37a8d64
Update SocialBanner.tsx (#6763)
kassens Apr 19, 2024
07cbd00
API docs for useDeferredValue's initialValue (#6747)
acdlite Apr 22, 2024
f8afd94
Add /link/new-jsx-transform (#6772)
rickhanlonii Apr 24, 2024
cdd2fdd
Add documentation for ref cleanup functions (#6770)
jackpope Apr 24, 2024
9fb2f0d
Move `use` to APIs (#6774)
kassens Apr 24, 2024
4f55010
Rename useFormState to useActionState (#6776)
kassens Apr 25, 2024
191852a
Add blog posts for React 19 Beta (#6778)
rickhanlonii Apr 25, 2024
412b733
Blog post nits (#6779)
rickhanlonii Apr 25, 2024
c8a316a
Blog typo
rickhanlonii Apr 25, 2024
0078b50
React19 blog post typos (#6780)
Zeko369 Apr 25, 2024
317dcf3
Fix code example in React-19 `useOptimistic` section (#6781)
gnoff Apr 25, 2024
9afcbf6
[React19-blog]: Make use(context) example easier to understand (#6783)
Zeko369 Apr 25, 2024
9aa8e82
refines the messaging to clarify that Server Components the feature i…
gnoff Apr 25, 2024
cdd0964
Fix react-helmet link (#6786)
gnoff Apr 25, 2024
526d7b4
Clarify React DOM APIs in React 19 Post (#6785)
rickhanlonii Apr 25, 2024
64beb65
Resources -> resources (#6787)
gnoff Apr 25, 2024
8cbed3e
Fix typos (#6788)
dom-zhu Apr 25, 2024
e09ff1c
Better use(Context) example in 19 blog (#6789)
rickhanlonii Apr 26, 2024
e45ac55
Better use(Promise) example in 19 blog (#6790)
rickhanlonii Apr 26, 2024
057f35c
Replaced all instances of /react to /rsc (#6797)
srikanth-kandi Apr 26, 2024
f664028
Updated react-19.md (#6796)
cbmongithub Apr 26, 2024
cf53cb5
Add rss feed (#6803)
rickhanlonii Apr 26, 2024
bc1020a
Update me
poteto Apr 26, 2024
845a281
Add redirects for moved rsc pages (#6800)
eps1lon Apr 26, 2024
807001c
chore: fix typo (#6791)
ChiaJune Apr 26, 2024
537bd05
to make examples consistent. (#6793)
Shubhdeep12 Apr 26, 2024
8c1c6e3
Add meta task for rss auto-discovery (#6805)
rickhanlonii Apr 26, 2024
01edd5c
Upgrade guide should recommend installing types `@beta` (#6806)
eps1lon Apr 26, 2024
9c53b48
Remove useless async (#6809)
Brooooooklyn Apr 29, 2024
3981ffe
Add versions page and nav version (#6814)
rickhanlonii Apr 30, 2024
86d306f
rm new redirects (#6816)
rickhanlonii Apr 30, 2024
6d0aca1
Fix punctuation. (#6815)
bozoputer Apr 30, 2024
e538800
Update react-19.md (#6813)
harish-sethuraman Apr 30, 2024
1df378f
uwu (#6817)
rickhanlonii Apr 30, 2024
3dd67d1
Fix type issues with `useActionState` docs (#6798)
eps1lon Apr 30, 2024
6f5ee38
uwu - add alt and instructions for turning off
rickhanlonii Apr 30, 2024
74697fb
fix uwu flicker (#6820)
rickhanlonii Apr 30, 2024
7062b8d
Update server-components.md - typo (#6823)
mootookoi May 1, 2024
bdb0d26
add uww toggle (#6824)
rickhanlonii May 1, 2024
0dbd67a
Add React Rally 2024 to conferences (#6819)
mzabriskie May 1, 2024
9e1f5cd
Add "Languages" navigation and article (#6382)
smikitky May 1, 2024
a2f8ff3
fix brand colors (#6826)
rickhanlonii May 1, 2024
a6450b9
Update uwu logo (#6827)
poteto May 2, 2024
e69ec58
rm survey and fix old links (#6828)
rickhanlonii May 2, 2024
d4a9a76
Fix typo in server-components.md (#6829)
seanWLawrence May 3, 2024
0e1ff1a
Fix React 19 upgrade guide typo (#6830)
Ryczko May 3, 2024
556063b
Add a redirect entry for feed.xml => rss.xml (#6836)
flexdinesh May 5, 2024
1fa2057
Update react-19.md (#6838)
HomyeeKing May 6, 2024
46437c2
Add missing period to React v18.0 blog post (#6842)
jackspiva May 7, 2024
0b9ae66
Add docs for useRef no no (#6846)
rickhanlonii May 9, 2024
f1b0f86
Fix typo on tutorial-tic-tac-toe.md (#6843)
skoryky May 10, 2024
f9b9b66
Fix #6852: navigation link fix (#6853)
Rekl0w May 10, 2024
4f1d985
Update synchronizing-with-effects.md (#6856)
segmentationfaulter May 10, 2024
b7bf6c1
Fix Node.js version update at `package.json` (#6855)
Rekl0w May 10, 2024
920aa65
merging all conflicts
react-translations-bot May 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add initial Rules of React docs (#6680)
This PR adds a new Rules of React reference section that covers the major rules that help developers author idiomatic React apps.

---------

Co-authored-by: Sathya Gunasekaran <[email protected]>
poteto and gsathya authored Mar 15, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 0dc1b315e54a54f381e26892c32d871cf86fe5eb
8 changes: 8 additions & 0 deletions src/content/reference/react/index.md
Original file line number Diff line number Diff line change
@@ -10,6 +10,14 @@ This section provides detailed reference documentation for working with React. F

The React reference documentation is broken down into functional subsections:

## Rules of React {/*rules-of-react*/}

React has idioms — or rules — for how to express patterns in a way that is easy to understand and yields high-quality applications:

* [Components and Hooks must be pure](/reference/rules/components-and-hooks-must-be-pure) – Purity makes your code easier to understand, debug, and allows React to automatically optimize your components and hooks correctly.
* [React calls Components and Hooks](/reference/rules/react-calls-components-and-hooks) – React is responsible for rendering components and hooks when necessary to optimize the user experience.
* [Rules of Hooks](/reference/rules/rules-of-hooks) – Hooks are defined using JavaScript functions, but they represent a special type of reusable UI logic with restrictions on where they can be called.

## React {/*react*/}

Programmatic React features:
364 changes: 364 additions & 0 deletions src/content/reference/rules/components-and-hooks-must-be-pure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,364 @@
---
title: Components and Hooks must be pure
---

<Intro>
Pure functions only perform a calculation and nothing more. It makes your code easier to understand, debug, and allows React to automatically optimize your components and hooks correctly.
</Intro>

<Note>
This reference page covers advanced topics and requires familiarity with the concepts covered in the [Keeping Components Pure](/learn/keeping-components-pure) page.
</Note>

<InlineToc />

### Why does purity matter? {/*why-does-purity-matter*/}

One of the key concepts that makes React, _React_ is _purity_. A pure component or hook is one that is:

* **Idempotent** – You [always get the same result everytime](/learn/keeping-components-pure#purity-components-as-formulas) you run it with the same inputs – props, state, context for component inputs; and arguments for hook inputs.
* **Has no side effects in render** – Code with side effects should run [**separately from rendering**](#how-does-react-run-your-code). For example as an [event handler](/learn/responding-to-events) – where the user interacts with the UI and causes it to update; or as an [Effect](/reference/react/useEffect) – which runs after render.
* **Does not mutate non-local values**: Components and hooks should [never modify values that aren't created locally](#mutation) in render.

When render is kept pure, React can understand how to prioritize which updates are most important for the user to see first. This is made possible because of render purity: since components don't have side effects [in render](#how-does-react-run-your-code), React can pause rendering components that aren't as important to update, and only come back to them later when it's needed.

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](#how-does-react-run-your-code) – 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. You can see an [example of this in the Keeping Components Pure page](/learn/keeping-components-pure#side-effects-unintended-consequences).

#### How does React run your code? {/*how-does-react-run-your-code*/}

React is declarative: you tell React _what_ to render, and React will figure out _how_ best to display it to your user. To do this, React has a few phases where it runs your code. You don't need to know about all of these phases to use React well. But at a high level, you should know about what code runs in _render_, and what runs outside of it.

_Rendering_ refers to calculating what the next version of your UI should look like. After rendering, [Effects](/reference/react/useEffect) are _flushed_ (meaning they are run until there are no more left) and may update the calculation if the Effects have impacts on layout. React takes this new calculation and compares it to the calulation used to create the previous version of your UI, then _commits_ just the minimum changes needed to the [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model) (what your user actually sees) to catch it up to the latest version.

<DeepDive>

#### How to tell if code runs in render {/*how-to-tell-if-code-runs-in-render*/}

One quick heuristic to tell if code runs during render is to examine where it is: if it's written at the top level like in the example below, there's a good chance it runs during render.

```js {2}
function Dropdown() {
const selectedItems = new Set(); // created during render
// ...
}
```

Event handlers and Effects don't run in render:

```js {4}
function Dropdown() {
const selectedItems = new Set();
const onSelect = (item) => {
// this code is in an event handler, so it's only run when the user triggers this
selectedItems.add(item);
}
}
```

```js {4}
function Dropdown() {
const selectedItems = new Set();
useEffect(() => {
// this code is inside of an Effect, so it only runs after rendering
logForAnalytics(selectedItems);
}, [selectedItems]);
}
```
</DeepDive>

---

## Components and hooks must be idempotent {/*components-and-hooks-must-be-idempotent*/}

Components must always return the same output with respect to their inputs – props, state, and context. This is known as _idempotency_. [Idempotency](https://en.wikipedia.org/wiki/Idempotence) is a term popularized in functional programming. It refers to the idea that you [always get the same result everytime](learn/keeping-components-pure) you run that piece of code with the same inputs.

This means that _all_ code that runs [during render](#how-does-react-run-your-code) 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):

```js {2}
function Clock() {
const time = new Date(); // 🔴 Bad: always returns a different result!
return <span>{time.toLocaleString()}</span>
}
```

`new Date()` 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.

This doesn't mean you shouldn't use non-idempotent functions like `new Date()` _at all_ – you should just avoid using them [during render](#how-does-react-run-your-code). In this case, we can _synchronize_ the latest date to this component using an [Effect](/reference/react/useEffect):

<Sandpack>

```js
import { useState, useEffect } from 'react';

function useTime() {
// 1. Keep track of the current date's state. `useState` receives an initializer function as its
// initial state. It only runs once when the hook is called, so only the current date at the
// time the hook is called is set first.
const [time, setTime] = useState(() => new Date());

useEffect(() => {
// 2. Update the current date every second using `setInterval`.
const id = setInterval(() => {
setTime(new Date()); // ✅ Good: non-idempotent code no longer runs in render
}, 1000);
// 3. Return a cleanup function so we don't leak the `setInterval` timer.
return () => clearInterval(id);
}, []);

return time;
}

export default function Clock() {
const time = useTime();
return <span>{time.toLocaleString()}</span>;
}
```

</Sandpack>

By wrapping the non-idempotent `new Date()` call in an Effect, it moves that calculation [outside of rendering](#how-does-react-run-your-code).

If you don't need to synchronize some external state with React, you can also consider using an [event handler](/learn/responding-to-events) if it only needs to be updated in response to a user interaction.

---

## Side effects must run outside of render {/*side-effects-must-run-outside-of-render*/}

[Side effects](/learn/keeping-components-pure#side-effects-unintended-consequences) should not run [in render](#how-does-react-run-your-code), as React can render components multiple times to create the best possible user experience.

<Note>
Side effects are a broader term than Effects. Effects specifically refer to code that's wrapped in `useEffect`, while a side effect is a general term for code that has any observable effect other than its primary result of returning a value to the caller.

Side effects are typically written inside of [event handlers](/learn/responding-to-events) or Effects. But never during render.
</Note>

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](#how-does-react-run-your-code), as React can render components multiple times. In most cases, you'll use [event handlers](learn/responding-to-events) to handle side effects. 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`.

### When is it okay to have mutation? {/*mutation*/}

#### Local mutation {/*local-mutation*/}
One common example of a side effect is mutation, which in JavaScript 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:

```js {2,7}
function FriendList({ friends }) {
const items = []; // ✅ Good: locally created
for (let i = 0; i < friends.length; i++) {
const friend = friends[i];
items.push(
<Friend key={friend.id} friend={friend} />
); // ✅ Good: local mutation is okay
}
return <section>{items}</section>;
}
```

There is no need to contort your code to avoid local mutation. [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) could also be used here for brevity, but there is nothing wrong with creating a local array and then pushing items into it [during render](#how-does-react-run-your-code).

Even though it looks like we are mutating `items`, the key point to note is that this code only does so _locally_ – the mutation isn't "remembered" when the component is rendered again. In other words, `items` only stays around as long as the component does. Because `items` is always _recreated_ every time `<FriendList />` is rendered, the component will always return the same result.

On the other hand, if `items` was created outside of the component, it holds on to its previous values and remembers changes:

```js {1,7}
const items = []; // 🔴 Bad: created outside of the component
function FriendList({ friends }) {
for (let i = 0; i < friends.length; i++) {
const friend = friends[i];
items.push(
<Friend key={friend.id} friend={friend} />
); // 🔴 Bad: mutates a value created outside of render
}
return <section>{items}</section>;
}
```

When `<FriendList />` runs again, we will continue appending `friends` to `items` every time that component is run, leading to multiple duplicated results. This version of `<FriendList />` has observable side effects [during render](#how-does-react-run-your-code) and **breaks the rule**.

#### Lazy initialization {/*lazy-initialization*/}

Lazy initialization is also fine despite not being fully "pure":

```js {2}
function ExpenseForm() {
SuperCalculator.initializeIfNotReady(); // ✅ Good: if it doesn't affect other components
// Continue rendering...
}
```

#### Changing the DOM {/*changing-the-dom*/}

Side effects that are directly visible to the user are not allowed in the render logic of React components. In other words, merely calling a component function shouldn’t by itself produce a change on the screen.

```js {2}
function ProductDetailPage({ product }) {
document.window.title = product.title; // 🔴 Bad: Changes the DOM
}
```

One way to achieve the desired result of updating `window.title` outside of render is to [synchronize the component with `window`](/learn/synchronizing-with-effects).

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-and-hooks-must-be-pure).

---

## Props and state are immutable {/*props-and-state-are-immutable*/}

A component's props and state are immutable [snapshots](learn/state-as-a-snapshot). Never mutate them directly. Instead, pass new props down, and use the setter function from `useState`.

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.

### Don't mutate Props {/*props*/}
Props are immutable because if you mutate them, the application will produce inconsistent output, which can be hard to debug since it may or may not work depending on the circumstance.

```js {2}
function Post({ item }) {
item.url = new Url(item.url, base); // 🔴 Bad: never mutate props directly
return <Link url={item.url}>{item.title}</Link>;
}
```

```js {2}
function Post({ item }) {
const url = new Url(item.url, base); // ✅ Good: make a copy instead
return <Link url={url}>{item.title}</Link>;
}
```

### Don't mutate State {/*state*/}
`useState` returns the state variable and a setter to update that state.

```js
const [stateVariable, setter] = useState(0);
```

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.

```js {5}
function Counter() {
const [count, setCount] = useState(0);

function handleClick() {
count = count + 1; // 🔴 Bad: never mutate state directly
}

return (
<button onClick={handleClick}>
You pressed me {count} times
</button>
);
}
```

```js {5}
function Counter() {
const [count, setCount] = useState(0);

function handleClick() {
setCount(count + 1); // ✅ Good: use the setter function returned by useState
}

return (
<button onClick={handleClick}>
You pressed me {count} times
</button>
);
}
```

---

## Return values and arguments to Hooks are immutable {/*return-values-and-arguments-to-hooks-are-immutable*/}

Once values are passed to a hook, you should not modify them. Like props in JSX, values become immutable when passed to a hook.

```js {4}
function useIconStyle(icon) {
const theme = useContext(ThemeContext);
if (icon.enabled) {
icon.className = computeStyle(icon, theme); // 🔴 Bad: never mutate hook arguments directly
}
return icon;
}
```

```js {3}
function useIconStyle(icon) {
const theme = useContext(ThemeContext);
const newIcon = { ...icon }; // ✅ Good: make a copy instead
if (icon.enabled) {
newIcon.className = computeStyle(icon, theme);
}
return newIcon;
}
```

One important principle in React is _local reasoning_: the ability to understand what a component or hook does by looking at its code in isolation. Hooks should be treated like "black boxes" when they are called. For example, a custom hook might have used its arguments as dependencies to memoize values inside it:

```js {4}
function useIconStyle(icon) {
const theme = useContext(ThemeContext);

return useMemo(() => {
const newIcon = { ...icon };
if (icon.enabled) {
newIcon.className = computeStyle(icon, theme);
}
return newIcon;
}, [icon, theme]);
}
```

If you were to mutate the hooks arguments, the custom hook's memoization will become incorrect, so it's important to avoid doing that.

```js {4}
style = useIconStyle(icon); // `style` is memoized based on `icon`
icon.enabled = false; // Bad: 🔴 never mutate hook arguments directly
style = useIconStyle(icon); // previously memoized result is returned
```

```js {4}
style = useIconStyle(icon); // `style` is memoized based on `icon`
icon = { ...icon, enabled: false }; // Good: ✅ make a copy instead
style = useIconStyle(icon); // new value of `style` is calculated
```

Similarly, it's important to not modify the return values of hooks, as they may have been memoized.

---

## Values are immutable after being passed to JSX {/*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.

When you use JSX in an expression, React may eagerly evaluate the JSX before the component finishes rendering. This means that mutating values after they've been passed to JSX can lead to outdated UIs, as React won't know to update the component's output.

```js {4}
function Page({ colour }) {
const styles = { colour, size: "large" };
const header = <Header styles={styles} />;
styles.size = "small"; // 🔴 Bad: styles was already used in the JSX above
const footer = <Footer styles={styles} />;
return (
<>
{header}
<Content />
{footer}
</>
);
}
```

```js {4}
function Page({ colour }) {
const headerStyles = { colour, size: "large" };
const header = <Header styles={headerStyles} />;
const footerStyles = { colour, size: "small" }; // ✅ Good: we created a new value
const footer = <Footer styles={footerStyles} />;
return (
<>
{header}
<Content />
{footer}
</>
);
}
```
52 changes: 52 additions & 0 deletions src/content/reference/rules/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
title: Rules of React
---

<Intro>
Just as different programming languages have their own ways of expressing concepts, React has its own idioms — or rules — for how to express patterns in a way that is easy to understand and yields high-quality applications.
</Intro>

<InlineToc />

---

<Note>
To learn more about expressing UIs with React, we recommend reading [Thinking in React](/learn/thinking-in-react).
</Note>

This section describes the rules you need to follow to write idiomatic React code. Writing idiomatic React code can help you write well organized, safe, and composable applications. These properties make your app more resilient to changes and makes it easier to work with other developers, libraries, and tools.

These rules are known as the **Rules of React**. They are rules – and not just guidelines – in the sense that if they are broken, your app likely has bugs. Your code also becomes unidiomatic and harder to understand and reason about.

We strongly recommend using [Strict Mode](/reference/react/StrictMode) alongside React's [ESLint plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) to help your codebase follow the Rules of React. By following the Rules of React, you'll be able to find and address these bugs and keep your application maintainable.

---

## Components and Hooks must be pure {/*components-and-hooks-must-be-pure*/}

[Purity in Components and Hooks](/reference/rules/components-and-hooks-must-be-pure) is a key rule of React that makes your app predictable, easy to debug, and allows React to automatically optimize your code.

* [Components must be idempotent](/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent) – React components are assumed to always return the same output with respect to their inputs – props, state, and context.
* [Side effects must run outside of render](/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) – Side effects should not run in render, as React can render components multiple times to create the best possible user experience.
* [Props and state are immutable](/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable) – A component’s props and state are immutable snapshots with respect to a single render. Never mutate them directly.
* [Return values and arguments to Hooks are immutable](/reference/rules/components-and-hooks-must-be-pure#return-values-and-arguments-to-hooks-are-immutable) – Once values are passed to a Hook, you should not modify them. Like props in JSX, values become immutable when passed to a Hook.
* [Values are immutable after being passed to JSX](/reference/rules/components-and-hooks-must-be-pure#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.

---

## React calls Components and Hooks {/*react-calls-components-and-hooks*/}

[React is responsible for rendering components and hooks when necessary to optimize the user experience.](/reference/rules/react-calls-components-and-hooks) It is declarative: you tell React what to render in your component’s logic, and React will figure out how best to display it to your user.

* [Never call component functions directly](/reference/rules/react-calls-components-and-hooks#never-call-component-functions-directly) – Components should only be used in JSX. Don’t call them as regular functions.
* [Never pass around hooks as regular values](/reference/rules/react-calls-components-and-hooks#never-pass-around-hooks-as-regular-values) – Hooks should only be called inside of components. Never pass it around as a regular value.

---

## Rules of Hooks {/*rules-of-hooks*/}

Hooks are defined using JavaScript functions, but they represent a special type of reusable UI logic with restrictions on where they can be called. You need to follow the [Rules of Hooks](/reference/rules/rules-of-hooks) when using them.

* [Only call Hooks at the top level](/reference/rules/rules-of-hooks#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.
* [Only call Hooks from React functions](/reference/rules/rules-of-hooks#only-call-hooks-from-react-functions) – Don’t call Hooks from regular JavaScript functions.

101 changes: 101 additions & 0 deletions src/content/reference/rules/react-calls-components-and-hooks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
title: React calls Components and Hooks
---

<Intro>
React is responsible for rendering components and hooks when necessary to optimize the user experience. It is declarative: you tell React what to render in your component’s logic, and React will figure out how best to display it to your user.
</Intro>

<InlineToc />

---

## Never call component functions directly {/*never-call-component-functions-directly*/}
Components should only be used in JSX. Don't call them as regular functions. React should call it.

React must decide when your component function is called [during rendering](/reference/rules/components-and-hooks-must-be-pure#how-does-react-run-your-code). In React, you do this using JSX.

```js {2}
function BlogPost() {
return <Layout><Article /></Layout>; // ✅ Good: Only use components in JSX
}
```

```js {2}
function BlogPost() {
return <Layout>{Article()}</Layout>; // 🔴 Bad: Never call them directly
}
```

If a component contains hooks, it's easy to violate the [Rules of Hooks](/reference/rules/rules-of-hooks) when components are called directly in a loop or conditionally.

Letting React orchestrate rendering also allows a number of benefits:

* **Components become more than functions.** React can augment them with features like _local state_ through Hooks that are tied to the component's identity in the tree.
* **Component types participate in reconciliation.** By letting React call your components, you also tell it more about the conceptual structure of your tree. For example, when you move from rendering `<Feed>` to the `<Profile>` page, React won’t attempt to re-use them.
* **React can enhance your user experience.** For example, it can let the browser do some work between component calls so that re-rendering a large component tree doesn’t block the main thread.
* **A better debugging story.** If components are first-class citizens that the library is aware of, we can build rich developer tools for introspection in development.
* **More efficient reconciliation.** React can decide exactly which components in the tree need re-rendering and skip over the ones that don't. That makes your app faster and more snappy.

---

## Never pass around hooks as regular values {/*never-pass-around-hooks-as-regular-values*/}

Hooks should only be called inside of components or hooks. Never pass it around as a regular value.

Hooks allow you to augment a component with React features. They should always be called as a function, and never passed around as a regular value. This enables _local reasoning_, or the ability for developers to understand everything a component can do by looking at that component in isolation.

Breaking this rule will cause React to not automatically optimize your component.

### Don't dynamically mutate a hook {/*dont-dynamically-mutate-a-hook*/}

Hooks should be as "static" as possible. This means you shouldn't dynamically mutate them. For example, this means you shouldn't write higher order hooks:

```js {2}
function ChatInput() {
const useDataWithLogging = withLogging(useData); // 🔴 Bad: don't write higher order hooks
const data = useDataWithLogging();
}
```

Hooks should be immutable and not be mutated. Instead of mutating a hook dynamically, create a static version of the hook with the desired functionality.

```js {2,6}
function ChatInput() {
const data = useDataWithLogging(); // ✅ Good: Create a new version of the hook
}

function useDataWithLogging() {
// ... Create a new version of the Hook and inline the logic here
}
```

### Don't dynamically use hooks {/*dont-dynamically-use-hooks*/}

Hooks should also not be dynamically used: for example, instead of doing dependency injection in a component by passing a hook as a value:

```js {2}
function ChatInput() {
return <Button useData={useDataWithLogging} /> // 🔴 Bad: don't pass hooks as props
}
```

You should always inline the call of the hook into that component and handle any logic in there.

```js {6}
function ChatInput() {
return <Button />
}

function Button() {
const data = useDataWithLogging(); // ✅ Good: Use the hook directly
}

function useDataWithLogging() {
// If there's any conditional logic to change the hook's behavior, it should be inlined into
// the hook
}
```

This way, `<Button />` is much easier to understand and debug. When Hooks are used in dynamic ways, it increases the complexity of your app greatly and inhibits local reasoning, making your team less productive in the long term. It also makes it easier to accidentally break the [Rules of Hooks](/reference/rules/rules-of-hooks) that hooks should not be called conditionally. If you find yourself needing to mock components for tests, it's better to mock the server instead to respond with canned data. If possible, it's also usually more effective to test your app with end-to-end tests.

135 changes: 135 additions & 0 deletions src/content/reference/rules/rules-of-hooks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
---
title: Rules of Hooks
---

<Intro>
Hooks are defined using JavaScript functions, but they represent a special type of reusable UI logic with restrictions on where they can be called.
</Intro>

<InlineToc />

---

## Only call Hooks at the top level {/*only-call-hooks-at-the-top-level*/}

Functions whose names start with `use` are called [*Hooks*](/reference/react) in React.

**Don’t call Hooks inside loops, conditions, nested functions, or `try`/`catch`/`finally` blocks.** Instead, always use Hooks at the top level of your React function, before any early returns. You can only call Hooks while React is rendering a function component:

* ✅ Call them at the top level in the body of a [function component](/learn/your-first-component).
* ✅ Call them at the top level in the body of a [custom Hook](/learn/reusing-logic-with-custom-hooks).

```js{2-3,8-9}
function Counter() {
// ✅ Good: top-level in a function component
const [count, setCount] = useState(0);
// ...
}
function useWindowWidth() {
// ✅ Good: top-level in a custom Hook
const [width, setWidth] = useState(window.innerWidth);
// ...
}
```

It’s **not** supported to call Hooks (functions starting with `use`) in any other cases, for example:

* 🔴 Do not call Hooks inside conditions or loops.
* 🔴 Do not call Hooks after a conditional `return` statement.
* 🔴 Do not call Hooks in event handlers.
* 🔴 Do not call Hooks in class components.
* 🔴 Do not call Hooks inside functions passed to `useMemo`, `useReducer`, or `useEffect`.
* 🔴 Do not call Hooks inside `try`/`catch`/`finally` blocks.

If you break these rules, you might see this error.

```js{3-4,11-12,20-21}
function Bad({ cond }) {
if (cond) {
// 🔴 Bad: inside a condition (to fix, move it outside!)
const theme = useContext(ThemeContext);
}
// ...
}
function Bad() {
for (let i = 0; i < 10; i++) {
// 🔴 Bad: inside a loop (to fix, move it outside!)
const theme = useContext(ThemeContext);
}
// ...
}
function Bad({ cond }) {
if (cond) {
return;
}
// 🔴 Bad: after a conditional return (to fix, move it before the return!)
const theme = useContext(ThemeContext);
// ...
}
function Bad() {
function handleClick() {
// 🔴 Bad: inside an event handler (to fix, move it outside!)
const theme = useContext(ThemeContext);
}
// ...
}
function Bad() {
const style = useMemo(() => {
// 🔴 Bad: inside useMemo (to fix, move it outside!)
const theme = useContext(ThemeContext);
return createStyle(theme);
});
// ...
}
class Bad extends React.Component {
render() {
// 🔴 Bad: inside a class component (to fix, write a function component instead of a class!)
useEffect(() => {})
// ...
}
}
function Bad() {
try {
// 🔴 Bad: inside try/catch/finally block (to fix, move it outside!)
const [x, setX] = useState(0);
} catch {
const [x, setX] = useState(1);
}
}
```

You can use the [`eslint-plugin-react-hooks` plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) to catch these mistakes.

<Note>

[Custom Hooks](/learn/reusing-logic-with-custom-hooks) *may* call other Hooks (that's their whole purpose). This works because custom Hooks are also supposed to only be called while a function component is rendering.

</Note>

---

## Only call Hooks from React functions {/*only-call-hooks-from-react-functions*/}

Don’t call Hooks from regular JavaScript functions. Instead, you can:

✅ Call Hooks from React function components.
✅ Call Hooks from [custom Hooks](/learn/reusing-logic-with-custom-hooks#extracting-your-own-custom-hook-from-a-component).

By following this rule, you ensure that all stateful logic in a component is clearly visible from its source code.

```js {2,5}
function FriendList() {
const [onlineStatus, setOnlineStatus] = useOnlineStatus(); //
}

function setOnlineStatus() { // ❌ Not a component or custom hook!
const [onlineStatus, setOnlineStatus] = useOnlineStatus();
}
```
20 changes: 20 additions & 0 deletions src/sidebarReference.json
Original file line number Diff line number Diff line change
@@ -350,6 +350,26 @@
}
]
},
{
"hasSectionHeader": true,
"sectionHeader": "Rules of React"
},
{
"title": "Overview",
"path": "/reference/rules"
},
{
"title": "Components and Hooks must be pure",
"path": "/reference/rules/components-and-hooks-must-be-pure"
},
{
"title": "React calls Components and Hooks",
"path": "/reference/rules/react-calls-components-and-hooks"
},
{
"title": "Rules of Hooks",
"path": "/reference/rules/rules-of-hooks"
},
{
"hasSectionHeader": true,
"sectionHeader": "Legacy APIs"