Skip to content

Commit

Permalink
Combine rules of jsx
Browse files Browse the repository at this point in the history
  • Loading branch information
poteto committed Mar 12, 2024
1 parent ac8bd9b commit 8e50692
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 81 deletions.
50 changes: 43 additions & 7 deletions src/content/reference/rules/components-and-hooks-must-be-pure.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: Components and Hooks must be pure
---

<Intro>
TODO
[Purity](/learn/keeping-components-pure) makes your code easier to understand and debug.
</Intro>

<InlineToc />
Expand Down Expand Up @@ -76,7 +76,7 @@ function FriendList({ friends }) {
There is no need to contort your code to avoid local mutation. In particular, [`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.
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 returns the same result.
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:
Expand Down Expand Up @@ -175,8 +175,7 @@ function Counter() {
## Return values and arguments to Hooks are immutable {/*return-values-and-arguments-to-hooks-are-immutable*/}
Once values are passed to a Hook, neither the calling code nor the Hook should
modify them. Like props in JSX, values become immutable when passed to a Hook.
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) {
Expand All @@ -201,8 +200,7 @@ function useIconStyle(icon) {
}
```
The custom Hook might have used the hook arguments as dependencies to memoize
values inside it.
The custom Hook might have used the hook arguments as dependencies to memoize values inside it.
```js {4}
function useIconStyle(icon) {
Expand Down Expand Up @@ -232,4 +230,42 @@ icon = { ...icon, enabled: false }; // ✅ 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 have been memoized.
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"; // ❌ 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" }; // ✅ we created a new value
const footer = <Footer styles={footerStyles} />;
return (
<>
{header}
<Content />
{footer}
</>
);
}
```
9 changes: 6 additions & 3 deletions src/content/reference/rules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@ We strongly recommend using Strict Mode alongside React's ESLint plugin to help

You can think of React's constraints like the grammatical rules and patterns of languages: they constrain what we can do with words, so that we can correctly and efficiently communicate our thoughts.

These rules have been used in the design of all of React's features over the years. React's Strict Mode enforces several of these rules at runtime in DEV mode, and with the release of React's upcoming compiler, more rules will now be statically checked to help you find more bugs as well as allow for correct optimization of your code.
These rules have been used in the design of all of React's features over the years. Enabling Strict Mode catches bugs caused by breaking these rules, and with the release of React's upcoming compiler, more rules will now be statically checked to help you find more bugs as well as allow for correct optimization of your code.

<Note>
Strict Mode checks are run in development mode only; they do not impact the production build.
</Note>

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.
</DeepDive>

* [Components and Hooks must be pure](/reference/rules/components-and-hooks-must-be-pure)
* [React orchestrates Components and Hooks](/reference/rules/react-orchestrates-components-and-hooks)
* [Rules of Hooks](/reference/rules/rules-of-hooks)
* [Rules of JSX](/reference/rules/rules-of-jsx)
* [Rules of Hooks](/reference/rules/rules-of-hooks)
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: React orchestrates Components and Hooks
---

<Intro>
TODO
React takes care of when your code runs for you so that your application has a great 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 />
Expand All @@ -13,17 +13,15 @@ TODO
## 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 takes care of _when_ your code runs for you so that your application has a great 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.

In order to do this, React must decide when your component function is called during rendering. In React, you do this using JSX.
React must decide when your component function is called during rendering. In React, you do this using JSX.

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

```js {3}
```js {2}
function BlogPost() {
return <Layout>{Article()}</Layout> // ❌ Never call them directly
}
Expand All @@ -47,28 +45,32 @@ Hooks allow you to augment a component with React features. They should always b

Passing around hooks as regular values also inhibits the compiler at performing optimizations. Breaking this rule will de-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); //
const data = useDataWithLogging();
}
```

```js {2}
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(); //
}
```

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
function useDataWithLogging() {
// ... Logic should go in here
// ... Create a new version of the Hook and inline the logic here
}
```

Hooks should also not be dynamically used: for example, instead of doing dependency injection in a component:
### 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() {
Expand All @@ -84,11 +86,12 @@ function ChatInput() {
}

function Button() {
const data = useDataWithLogging();
const data = useDataWithLogging(); //
}

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

Expand Down
5 changes: 1 addition & 4 deletions src/content/reference/rules/rules-of-hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: Rules of Hooks
---

<Intro>
TODO
Hooks are JavaScript functions, but you need to follow two rules when using them. We provide a [linter plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) to enforce these rules automatically.
</Intro>

<InlineToc />
Expand Down Expand Up @@ -115,6 +115,3 @@ function setOnlineStatus() { // ❌ Not a component or custom hook!
const [onlineStatus, setOnlineStatus] = useOnlineStatus();
}
```

## Return values and arguments to Hooks are immutable {/*return-values-and-arguments-to-hooks-are-immutable*/}
TODO
49 changes: 0 additions & 49 deletions src/content/reference/rules/rules-of-jsx.md

This file was deleted.

4 changes: 0 additions & 4 deletions src/sidebarReference.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@
{
"title": "Rules of Hooks",
"path": "/reference/rules/rules-of-hooks"
},
{
"title": "Rules of JSX",
"path": "/reference/rules/rules-of-jsx"
}
]
},
Expand Down

0 comments on commit 8e50692

Please sign in to comment.