remove all trailing whitespaces in src/content

This commit is contained in:
Matt Carroll
2023-10-20 15:08:33 -07:00
parent 16f90a936a
commit 1922d57a19
65 changed files with 543 additions and 543 deletions

View File

@@ -276,17 +276,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
isPacked={true}
name="Space suit"
<Item
isPacked={true}
name="Space suit"
/>
<Item
isPacked={true}
name="Helmet with a golden leaf"
<Item
isPacked={true}
name="Helmet with a golden leaf"
/>
<Item
isPacked={false}
name="Photo of Tam"
<Item
isPacked={false}
name="Photo of Tam"
/>
</ul>
</section>
@@ -314,17 +314,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
isPacked={true}
name="Space suit"
<Item
isPacked={true}
name="Space suit"
/>
<Item
isPacked={true}
name="Helmet with a golden leaf"
<Item
isPacked={true}
name="Helmet with a golden leaf"
/>
<Item
isPacked={false}
name="Photo of Tam"
<Item
isPacked={false}
name="Photo of Tam"
/>
</ul>
</section>
@@ -362,17 +362,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
importance={9}
name="Space suit"
<Item
importance={9}
name="Space suit"
/>
<Item
importance={0}
name="Helmet with a golden leaf"
<Item
importance={0}
name="Helmet with a golden leaf"
/>
<Item
importance={6}
name="Photo of Tam"
<Item
importance={6}
name="Photo of Tam"
/>
</ul>
</section>
@@ -406,17 +406,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
importance={9}
name="Space suit"
<Item
importance={9}
name="Space suit"
/>
<Item
importance={0}
name="Helmet with a golden leaf"
<Item
importance={0}
name="Helmet with a golden leaf"
/>
<Item
importance={6}
name="Photo of Tam"
<Item
importance={6}
name="Photo of Tam"
/>
</ul>
</section>

View File

@@ -11,7 +11,7 @@ Do you know of a local React.js conference? Add it here! (Please keep the list c
## Upcoming Conferences {/*upcoming-conferences*/}
### RedwoodJS Conference 2023 {/*redwoodjs-conference-2023*/}
September 26 - 29, 2023. Grants Pass, Oregon + remote (hybrid event)
September 26 - 29, 2023. Grants Pass, Oregon + remote (hybrid event)
[Website](https://www.redwoodjsconf.com/) - [Twitter](https://twitter.com/redwoodjs)

View File

@@ -51,7 +51,7 @@ Current members of the React team are listed in alphabetical order below.
</TeamMember>
<TeamMember name="Luna Wei" permalink="luna-wei" photo="/images/team/luna-wei.jpg" github="lunaleaps" twitter="lunaleaps" title="Engineer at Meta">
Luna first learnt the fundamentals of python at the age of 6 from her father. Since then, she has been unstoppable. Luna aspires to be a gen z, and the road to success is paved with environmental advocacy, urban gardening and lots of quality time with her Voo-Dood (as pictured).
Luna first learnt the fundamentals of python at the age of 6 from her father. Since then, she has been unstoppable. Luna aspires to be a gen z, and the road to success is paved with environmental advocacy, urban gardening and lots of quality time with her Voo-Dood (as pictured).
</TeamMember>
<TeamMember name="Matt Carroll" permalink="matt-carroll" photo="/images/team/matt-carroll.png" github="mattcarrollcode" twitter="mattcarrollcode" title="Developer Advocate at Meta">

View File

@@ -458,7 +458,7 @@ export default function Menu() {
return (
<>
<h2>What's your travel snack?</h2>
<h2>What's your travel snack?</h2>
<ul>
{items.map((item, index) => (
<li key={item.id}>
@@ -806,7 +806,7 @@ export const initialTravelPlan = {
}, {
id: 48,
title: 'Green Hill',
childPlaces: []
childPlaces: []
}]
}]
};
@@ -884,7 +884,7 @@ export const initialTravelPlan = {
id: 2,
title: 'Africa',
childIds: [3, 4, 5, 6 , 7, 8, 9]
},
},
3: {
id: 3,
title: 'Botswana',
@@ -904,7 +904,7 @@ export const initialTravelPlan = {
id: 6,
title: 'Madagascar',
childIds: []
},
},
7: {
id: 7,
title: 'Morocco',
@@ -923,7 +923,7 @@ export const initialTravelPlan = {
10: {
id: 10,
title: 'Americas',
childIds: [11, 12, 13, 14, 15, 16, 17, 18],
childIds: [11, 12, 13, 14, 15, 16, 17, 18],
},
11: {
id: 11,
@@ -939,7 +939,7 @@ export const initialTravelPlan = {
id: 13,
title: 'Barbados',
childIds: []
},
},
14: {
id: 14,
title: 'Canada',
@@ -968,7 +968,7 @@ export const initialTravelPlan = {
19: {
id: 19,
title: 'Asia',
childIds: [20, 21, 22, 23, 24, 25],
childIds: [20, 21, 22, 23, 24, 25],
},
20: {
id: 20,
@@ -1003,7 +1003,7 @@ export const initialTravelPlan = {
26: {
id: 26,
title: 'Europe',
childIds: [27, 28, 29, 30, 31, 32, 33],
childIds: [27, 28, 29, 30, 31, 32, 33],
},
27: {
id: 27,
@@ -1043,7 +1043,7 @@ export const initialTravelPlan = {
34: {
id: 34,
title: 'Oceania',
childIds: [35, 36, 37, 38, 39, 40, 41],
childIds: [35, 36, 37, 38, 39, 40, 41],
},
35: {
id: 35,
@@ -1220,7 +1220,7 @@ export const initialTravelPlan = {
id: 2,
title: 'Africa',
childIds: [3, 4, 5, 6 , 7, 8, 9]
},
},
3: {
id: 3,
title: 'Botswana',
@@ -1240,7 +1240,7 @@ export const initialTravelPlan = {
id: 6,
title: 'Madagascar',
childIds: []
},
},
7: {
id: 7,
title: 'Morocco',
@@ -1259,7 +1259,7 @@ export const initialTravelPlan = {
10: {
id: 10,
title: 'Americas',
childIds: [11, 12, 13, 14, 15, 16, 17, 18],
childIds: [11, 12, 13, 14, 15, 16, 17, 18],
},
11: {
id: 11,
@@ -1275,7 +1275,7 @@ export const initialTravelPlan = {
id: 13,
title: 'Barbados',
childIds: []
},
},
14: {
id: 14,
title: 'Canada',
@@ -1304,7 +1304,7 @@ export const initialTravelPlan = {
19: {
id: 19,
title: 'Asia',
childIds: [20, 21, 22, 23, 24, 25],
childIds: [20, 21, 22, 23, 24, 25],
},
20: {
id: 20,
@@ -1339,7 +1339,7 @@ export const initialTravelPlan = {
26: {
id: 26,
title: 'Europe',
childIds: [27, 28, 29, 30, 31, 32, 33],
childIds: [27, 28, 29, 30, 31, 32, 33],
},
27: {
id: 27,
@@ -1379,7 +1379,7 @@ export const initialTravelPlan = {
34: {
id: 34,
title: 'Oceania',
childIds: [35, 36, 37, 38, 39, 40, 41],
childIds: [35, 36, 37, 38, 39, 40, 41],
},
35: {
id: 35,
@@ -1559,7 +1559,7 @@ export const initialTravelPlan = {
id: 2,
title: 'Africa',
childIds: [3, 4, 5, 6 , 7, 8, 9]
},
},
3: {
id: 3,
title: 'Botswana',
@@ -1579,7 +1579,7 @@ export const initialTravelPlan = {
id: 6,
title: 'Madagascar',
childIds: []
},
},
7: {
id: 7,
title: 'Morocco',
@@ -1598,7 +1598,7 @@ export const initialTravelPlan = {
10: {
id: 10,
title: 'Americas',
childIds: [11, 12, 13, 14, 15, 16, 17, 18],
childIds: [11, 12, 13, 14, 15, 16, 17, 18],
},
11: {
id: 11,
@@ -1614,7 +1614,7 @@ export const initialTravelPlan = {
id: 13,
title: 'Barbados',
childIds: []
},
},
14: {
id: 14,
title: 'Canada',
@@ -1643,7 +1643,7 @@ export const initialTravelPlan = {
19: {
id: 19,
title: 'Asia',
childIds: [20, 21, 22, 23, 24, 25,],
childIds: [20, 21, 22, 23, 24, 25,],
},
20: {
id: 20,
@@ -1678,7 +1678,7 @@ export const initialTravelPlan = {
26: {
id: 26,
title: 'Europe',
childIds: [27, 28, 29, 30, 31, 32, 33],
childIds: [27, 28, 29, 30, 31, 32, 33],
},
27: {
id: 27,
@@ -1718,7 +1718,7 @@ export const initialTravelPlan = {
34: {
id: 34,
title: 'Oceania',
childIds: [35, 36, 37, 38, 39, 40,, 41],
childIds: [35, 36, 37, 38, 39, 40,, 41],
},
35: {
id: 35,
@@ -1823,7 +1823,7 @@ Sometimes, you can also reduce state nesting by moving some of the nested state
<Recap>
* If two state variables always update together, consider merging them into one.
* If two state variables always update together, consider merging them into one.
* Choose your state variables carefully to avoid creating "impossible" states.
* Structure your state in a way that reduces the chances that you'll make a mistake updating it.
* Avoid redundant and duplicate state so that you don't need to keep it in sync.
@@ -2062,7 +2062,7 @@ export default function TravelPlan() {
}
return (
<>
<>
<AddItem
onAddItem={handleAddItem}
/>
@@ -2197,7 +2197,7 @@ export default function TravelPlan() {
}
return (
<>
<>
<AddItem
onAddItem={handleAddItem}
/>
@@ -2350,7 +2350,7 @@ export default function Letter({
isHighlighted ? 'highlighted' : ''
}
onFocus={() => {
onHover(letter);
onHover(letter);
}}
onPointerMove={() => {
onHover(letter);
@@ -2459,7 +2459,7 @@ export default function Letter({
isHighlighted ? 'highlighted' : ''
}
onFocus={() => {
onHover(letter.id);
onHover(letter.id);
}}
onPointerMove={() => {
onHover(letter.id);

View File

@@ -32,17 +32,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
isPacked={true}
name="Space suit"
<Item
isPacked={true}
name="Space suit"
/>
<Item
isPacked={true}
name="Helmet with a golden leaf"
<Item
isPacked={true}
name="Helmet with a golden leaf"
/>
<Item
isPacked={false}
name="Photo of Tam"
<Item
isPacked={false}
name="Photo of Tam"
/>
</ul>
</section>
@@ -80,17 +80,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
isPacked={true}
name="Space suit"
<Item
isPacked={true}
name="Space suit"
/>
<Item
isPacked={true}
name="Helmet with a golden leaf"
<Item
isPacked={true}
name="Helmet with a golden leaf"
/>
<Item
isPacked={false}
name="Photo of Tam"
<Item
isPacked={false}
name="Photo of Tam"
/>
</ul>
</section>
@@ -132,17 +132,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
isPacked={true}
name="Space suit"
<Item
isPacked={true}
name="Space suit"
/>
<Item
isPacked={true}
name="Helmet with a golden leaf"
<Item
isPacked={true}
name="Helmet with a golden leaf"
/>
<Item
isPacked={false}
name="Photo of Tam"
<Item
isPacked={false}
name="Photo of Tam"
/>
</ul>
</section>
@@ -236,17 +236,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
isPacked={true}
name="Space suit"
<Item
isPacked={true}
name="Space suit"
/>
<Item
isPacked={true}
name="Helmet with a golden leaf"
<Item
isPacked={true}
name="Helmet with a golden leaf"
/>
<Item
isPacked={false}
name="Photo of Tam"
<Item
isPacked={false}
name="Photo of Tam"
/>
</ul>
</section>
@@ -290,17 +290,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
isPacked={true}
name="Space suit"
<Item
isPacked={true}
name="Space suit"
/>
<Item
isPacked={true}
name="Helmet with a golden leaf"
<Item
isPacked={true}
name="Helmet with a golden leaf"
/>
<Item
isPacked={false}
name="Photo of Tam"
<Item
isPacked={false}
name="Photo of Tam"
/>
</ul>
</section>
@@ -371,17 +371,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
isPacked={true}
name="Space suit"
<Item
isPacked={true}
name="Space suit"
/>
<Item
isPacked={true}
name="Helmet with a golden leaf"
<Item
isPacked={true}
name="Helmet with a golden leaf"
/>
<Item
isPacked={false}
name="Photo of Tam"
<Item
isPacked={false}
name="Photo of Tam"
/>
</ul>
</section>
@@ -417,17 +417,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
isPacked={true}
name="Space suit"
<Item
isPacked={true}
name="Space suit"
/>
<Item
isPacked={true}
name="Helmet with a golden leaf"
<Item
isPacked={true}
name="Helmet with a golden leaf"
/>
<Item
isPacked={false}
name="Photo of Tam"
<Item
isPacked={false}
name="Photo of Tam"
/>
</ul>
</section>
@@ -474,17 +474,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
isPacked={true}
name="Space suit"
<Item
isPacked={true}
name="Space suit"
/>
<Item
isPacked={true}
name="Helmet with a golden leaf"
<Item
isPacked={true}
name="Helmet with a golden leaf"
/>
<Item
isPacked={false}
name="Photo of Tam"
<Item
isPacked={false}
name="Photo of Tam"
/>
</ul>
</section>
@@ -512,17 +512,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
isPacked={true}
name="Space suit"
<Item
isPacked={true}
name="Space suit"
/>
<Item
isPacked={true}
name="Helmet with a golden leaf"
<Item
isPacked={true}
name="Helmet with a golden leaf"
/>
<Item
isPacked={false}
name="Photo of Tam"
<Item
isPacked={false}
name="Photo of Tam"
/>
</ul>
</section>
@@ -560,17 +560,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
importance={9}
name="Space suit"
<Item
importance={9}
name="Space suit"
/>
<Item
importance={0}
name="Helmet with a golden leaf"
<Item
importance={0}
name="Helmet with a golden leaf"
/>
<Item
importance={6}
name="Photo of Tam"
<Item
importance={6}
name="Photo of Tam"
/>
</ul>
</section>
@@ -604,17 +604,17 @@ export default function PackingList() {
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
importance={9}
name="Space suit"
<Item
importance={9}
name="Space suit"
/>
<Item
importance={0}
name="Helmet with a golden leaf"
<Item
importance={0}
name="Helmet with a golden leaf"
/>
<Item
importance={6}
name="Photo of Tam"
<Item
importance={6}
name="Photo of Tam"
/>
</ul>
</section>

View File

@@ -526,19 +526,19 @@ Read **[Keeping Components Pure](/learn/keeping-components-pure)** to learn how
## Your UI as a tree {/*your-ui-as-a-tree*/}
React uses trees to model the relationships between components and modules.
React uses trees to model the relationships between components and modules.
A React render tree is a representation of the parent and child relationship between components.
A React render tree is a representation of the parent and child relationship between components.
<Diagram name="generic_render_tree" height={250} width={500} alt="A tree graph with five nodes, with each node representing a component. The root node is located at the top the tree graph and is labelled 'Root Component'. It has two arrows extending down to two nodes labelled 'Component A' and 'Component C'. Each of the arrows is labelled with 'renders'. 'Component A' has a single 'renders' arrow to a node labelled 'Component B'. 'Component C' has a single 'renders' arrow to a node labelled 'Component D'.">An example React render tree.</Diagram>
Components near the top of the tree, near the root component, are considered top-level components. Components with no child components are leaf components. This categorization of components is useful for understanding data flow and rendering performance.
Modelling the relationship between JavaScript modules is another useful way to understand your app. We refer to it as a module dependency tree.
Modelling the relationship between JavaScript modules is another useful way to understand your app. We refer to it as a module dependency tree.
<Diagram name="generic_dependency_tree" height={250} width={500} alt="A tree graph with five nodes. Each node represents a JavaScript module. The top-most node is labelled 'RootModule.js'. It has three arrows extending to the nodes: 'ModuleA.js', 'ModuleB.js', and 'ModuleC.js'. Each arrow is labelled as 'imports'. 'ModuleC.js' node has a single 'imports' arrow that points to a node labelled 'ModuleD.js'.">An example module dependency tree.</Diagram>
A dependency tree is often used by build tools to bundle all the relevant JavaScript code for the client to download and render. A large bundle size regresses user experience for React apps. Understanding the module dependency tree is helpful to debug such issues.
A dependency tree is often used by build tools to bundle all the relevant JavaScript code for the client to download and render. A large bundle size regresses user experience for React apps. Understanding the module dependency tree is helpful to debug such issues.
<LearnMore path="/learn/understanding-your-ui-as-a-tree">

View File

@@ -31,7 +31,7 @@ Some editors come with these features built in, but others might require adding
### Linting {/*linting*/}
Code linters find problems in your code as you write, helping you fix them early. [ESLint](https://eslint.org/) is a popular, open source linter for JavaScript.
Code linters find problems in your code as you write, helping you fix them early. [ESLint](https://eslint.org/) is a popular, open source linter for JavaScript.
* [Install ESLint with the recommended configuration for React](https://www.npmjs.com/package/eslint-config-react-app) (be sure you have [Node installed!](https://nodejs.org/en/download/current/))
* [Integrate ESLint in VSCode with the official extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)

View File

@@ -227,7 +227,7 @@ function Form() {
}
```
However, you *do* need Effects to synchronize with external systems.
However, you *do* need Effects to synchronize with external systems.
<LearnMore path="/learn/you-might-not-need-an-effect">
@@ -388,7 +388,7 @@ export default function App() {
<hr />
<ChatRoom
roomId={roomId}
theme={isDark ? 'dark' : 'light'}
theme={isDark ? 'dark' : 'light'}
/>
</>
);
@@ -521,7 +521,7 @@ export default function App() {
<hr />
<ChatRoom
roomId={roomId}
theme={isDark ? 'dark' : 'light'}
theme={isDark ? 'dark' : 'light'}
/>
</>
);

View File

@@ -118,7 +118,7 @@ Notice how this example is broken down into two component files now:
You may encounter files that leave off the `.js` file extension like so:
```js
```js
import Gallery from './Gallery';
```

View File

@@ -27,13 +27,13 @@ You might already be familiar with one example of pure functions: formulas in ma
Consider this math formula: <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math>.
If <Math><MathI>x</MathI> = 2</Math> then <Math><MathI>y</MathI> = 4</Math>. Always.
If <Math><MathI>x</MathI> = 2</Math> then <Math><MathI>y</MathI> = 4</Math>. Always.
If <Math><MathI>x</MathI> = 3</Math> then <Math><MathI>y</MathI> = 6</Math>. Always.
If <Math><MathI>x</MathI> = 3</Math> then <Math><MathI>y</MathI> = 6</Math>. Always.
If <Math><MathI>x</MathI> = 3</Math>, <MathI>y</MathI> won't sometimes be <Math>9</Math> or <Math>1</Math> or <Math>2.5</Math> depending on the time of day or the state of the stock market.
If <Math><MathI>x</MathI> = 3</Math>, <MathI>y</MathI> won't sometimes be <Math>9</Math> or <Math>1</Math> or <Math>2.5</Math> depending on the time of day or the state of the stock market.
If <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math> and <Math><MathI>x</MathI> = 3</Math>, <MathI>y</MathI> will _always_ be <Math>6</Math>.
If <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math> and <Math><MathI>x</MathI> = 3</Math>, <MathI>y</MathI> will _always_ be <Math>6</Math>.
If we made this into a JavaScript function, it would look like this:
@@ -52,7 +52,7 @@ React is designed around this concept. **React assumes that every component you
```js App.js
function Recipe({ drinkers }) {
return (
<ol>
<ol>
<li>Boil {drinkers} cups of water.</li>
<li>Add {drinkers} spoons of tea and {0.5 * drinkers} spoons of spice.</li>
<li>Add {0.5 * drinkers} cups of milk to boil and sugar to taste.</li>
@@ -75,11 +75,11 @@ export default function App() {
</Sandpack>
When you pass `drinkers={2}` to `Recipe`, it will return JSX containing `2 cups of water`. Always.
When you pass `drinkers={2}` to `Recipe`, it will return JSX containing `2 cups of water`. Always.
If you pass `drinkers={4}`, it will return JSX containing `4 cups of water`. Always.
Just like a math formula.
Just like a math formula.
You could think of your components as recipes: if you follow them and don't introduce new ingredients during the cooking process, you will get the same dish every time. That "dish" is the JSX that the component serves to React to [render.](/learn/render-and-commit)
@@ -217,7 +217,7 @@ Every new React feature we're building takes advantage of purity. From data fetc
* A component must be pure, meaning:
* **It minds its own business.** It should not change any objects or variables that existed before rendering.
* **Same inputs, same output.** Given the same inputs, a component should always return the same JSX.
* **Same inputs, same output.** Given the same inputs, a component should always return the same JSX.
* Rendering can happen at any time, so components should not depend on each others' rendering sequence.
* You should not mutate any of the inputs that your components use for rendering. That includes props, state, and context. To update the screen, ["set" state](/learn/state-a-components-memory) instead of mutating preexisting objects.
* Strive to express your component's logic in the JSX you return. When you need to "change things", you'll usually want to do it in an event handler. As a last resort, you can `useEffect`.
@@ -226,7 +226,7 @@ Every new React feature we're building takes advantage of purity. From data fetc
</Recap>
<Challenges>
#### Fix a broken clock {/*fix-a-broken-clock*/}

View File

@@ -293,7 +293,7 @@ You might be wondering how React knew that your Effect needed to re-synchronize
```js {1,3,8}
function ChatRoom({ roomId }) { // The roomId prop may change over time
useEffect(() => {
const connection = createConnection(serverUrl, roomId); // This Effect reads roomId
const connection = createConnection(serverUrl, roomId); // This Effect reads roomId
connection.connect();
return () => {
connection.disconnect();
@@ -969,7 +969,7 @@ export default function App() {
<label>
<input type="checkbox"
checked={canMove}
onChange={e => setCanMove(e.target.checked)}
onChange={e => setCanMove(e.target.checked)}
/>
The dot is allowed to move
</label>
@@ -1027,7 +1027,7 @@ export default function App() {
<label>
<input type="checkbox"
checked={canMove}
onChange={e => setCanMove(e.target.checked)}
onChange={e => setCanMove(e.target.checked)}
/>
The dot is allowed to move
</label>
@@ -1083,7 +1083,7 @@ export default function App() {
<label>
<input type="checkbox"
checked={canMove}
onChange={e => setCanMove(e.target.checked)}
onChange={e => setCanMove(e.target.checked)}
/>
The dot is allowed to move
</label>
@@ -1155,7 +1155,7 @@ export default function App() {
<label>
<input type="checkbox"
checked={canMove}
onChange={e => setCanMove(e.target.checked)}
onChange={e => setCanMove(e.target.checked)}
/>
The dot is allowed to move
</label>
@@ -1220,7 +1220,7 @@ export default function App() {
<label>
<input type="checkbox"
checked={canMove}
onChange={e => setCanMove(e.target.checked)}
onChange={e => setCanMove(e.target.checked)}
/>
The dot is allowed to move
</label>
@@ -1279,7 +1279,7 @@ export default function App() {
<label>
<input type="checkbox"
checked={canMove}
onChange={e => setCanMove(e.target.checked)}
onChange={e => setCanMove(e.target.checked)}
/>
The dot is allowed to move
</label>
@@ -1711,7 +1711,7 @@ async function fetchPlanets() {
name: 'Venus'
}, {
id: 'mars',
name: 'Mars'
name: 'Mars'
}]);
}, 1000);
});
@@ -1735,7 +1735,7 @@ async function fetchPlaces(planetId) {
name: 'Spain'
}, {
id: 'vietnam',
name: 'Vietnam'
name: 'Vietnam'
}]);
} else if (planetId === 'venus') {
resolve([{
@@ -1746,7 +1746,7 @@ async function fetchPlaces(planetId) {
name: 'Diana Chasma'
}, {
id: 'kumsong-vallis',
name: 'Kŭmsŏng Vallis'
name: 'Kŭmsŏng Vallis'
}]);
} else if (planetId === 'mars') {
resolve([{
@@ -1879,7 +1879,7 @@ async function fetchPlanets() {
name: 'Venus'
}, {
id: 'mars',
name: 'Mars'
name: 'Mars'
}]);
}, 1000);
});
@@ -1903,7 +1903,7 @@ async function fetchPlaces(planetId) {
name: 'Spain'
}, {
id: 'vietnam',
name: 'Vietnam'
name: 'Vietnam'
}]);
} else if (planetId === 'venus') {
resolve([{
@@ -1914,7 +1914,7 @@ async function fetchPlaces(planetId) {
name: 'Diana Chasma'
}, {
id: 'kumsong-vallis',
name: 'Kŭmsŏng Vallis'
name: 'Kŭmsŏng Vallis'
}]);
} else if (planetId === 'mars') {
resolve([{
@@ -2042,7 +2042,7 @@ async function fetchPlanets() {
name: 'Venus'
}, {
id: 'mars',
name: 'Mars'
name: 'Mars'
}]);
}, 1000);
});
@@ -2066,7 +2066,7 @@ async function fetchPlaces(planetId) {
name: 'Spain'
}, {
id: 'vietnam',
name: 'Vietnam'
name: 'Vietnam'
}]);
} else if (planetId === 'venus') {
resolve([{
@@ -2077,7 +2077,7 @@ async function fetchPlaces(planetId) {
name: 'Diana Chasma'
}, {
id: 'kumsong-vallis',
name: 'Kŭmsŏng Vallis'
name: 'Kŭmsŏng Vallis'
}]);
} else if (planetId === 'mars') {
resolve([{

View File

@@ -442,8 +442,8 @@ In the above example, `MyInput` exposes the original DOM input element. This let
```js
import {
forwardRef,
useRef,
forwardRef,
useRef,
useImperativeHandle
} from 'react';
@@ -590,7 +590,7 @@ export default function TodoList() {
const newTodo = { id: nextId++, text: text };
flushSync(() => {
setText('');
setTodos([ ...todos, newTodo]);
setTodos([ ...todos, newTodo]);
});
listRef.current.lastChild.scrollIntoView({
behavior: 'smooth',
@@ -1004,7 +1004,7 @@ export default function CatFriends() {
behavior: 'smooth',
block: 'nearest',
inline: 'center'
});
});
}}>
Next
</button>

View File

@@ -857,7 +857,7 @@ If neither of these approaches works well for you, consider context.
* **Current account:** Many components might need to know the currently logged in user. Putting it in context makes it convenient to read it anywhere in the tree. Some apps also let you operate multiple accounts at the same time (e.g. to leave a comment as a different user). In those cases, it can be convenient to wrap a part of the UI into a nested provider with a different current account value.
* **Routing:** Most routing solutions use context internally to hold the current route. This is how every link "knows" whether it's active or not. If you build your own router, you might want to do it too.
* **Managing state:** As your app grows, you might end up with a lot of state closer to the top of your app. Many distant components below may want to change it. It is common to [use a reducer together with context](/learn/scaling-up-with-reducer-and-context) to manage complex state and pass it down to distant components without too much hassle.
Context is not limited to static values. If you pass a different value on the next render, React will update all the components reading it below! This is why context is often used in combination with state.
In general, if some information is needed by distant components in different parts of the tree, it's a good indication that context will help you.
@@ -963,27 +963,27 @@ export const places = [{
description: 'The tradition of choosing bright colors for houses began in the late 20th century.',
imageId: 'K9HVAGH'
}, {
id: 1,
id: 1,
name: 'Rainbow Village in Taichung, Taiwan',
description: 'To save the houses from demolition, Huang Yung-Fu, a local resident, painted all 1,200 of them in 1924.',
imageId: '9EAYZrt'
}, {
id: 2,
id: 2,
name: 'Macromural de Pachuca, Mexico',
description: 'One of the largest murals in the world covering homes in a hillside neighborhood.',
imageId: 'DgXHVwu'
}, {
id: 3,
id: 3,
name: 'Selarón Staircase in Rio de Janeiro, Brazil',
description: 'This landmark was created by Jorge Selarón, a Chilean-born artist, as a "tribute to the Brazilian people."',
imageId: 'aeO3rpI'
}, {
id: 4,
id: 4,
name: 'Burano, Italy',
description: 'The houses are painted following a specific color system dating back to 16th century.',
imageId: 'kxsph5C'
}, {
id: 5,
id: 5,
name: 'Chefchaouen, Marocco',
description: 'There are a few theories on why the houses are painted blue, including that the color repells mosquitos or that it symbolizes sky and heaven.',
imageId: 'rTqKo46'
@@ -1007,9 +1007,9 @@ export function getImageUrl(place) {
```css
ul { list-style-type: none; padding: 0px 10px; }
li {
margin-bottom: 10px;
display: grid;
li {
margin-bottom: 10px;
display: grid;
grid-template-columns: auto 1fr;
gap: 20px;
align-items: center;
@@ -1102,27 +1102,27 @@ export const places = [{
description: 'The tradition of choosing bright colors for houses began in the late 20th century.',
imageId: 'K9HVAGH'
}, {
id: 1,
id: 1,
name: 'Rainbow Village in Taichung, Taiwan',
description: 'To save the houses from demolition, Huang Yung-Fu, a local resident, painted all 1,200 of them in 1924.',
imageId: '9EAYZrt'
}, {
id: 2,
id: 2,
name: 'Macromural de Pachuca, Mexico',
description: 'One of the largest murals in the world covering homes in a hillside neighborhood.',
imageId: 'DgXHVwu'
}, {
id: 3,
id: 3,
name: 'Selarón Staircase in Rio de Janeiro, Brazil',
description: 'This landmark was created by Jorge Selarón, a Chilean-born artist, as a "tribute to the Brazilian people".',
imageId: 'aeO3rpI'
}, {
id: 4,
id: 4,
name: 'Burano, Italy',
description: 'The houses are painted following a specific color system dating back to 16th century.',
imageId: 'kxsph5C'
}, {
id: 5,
id: 5,
name: 'Chefchaouen, Marocco',
description: 'There are a few theories on why the houses are painted blue, including that the color repells mosquitos or that it symbolizes sky and heaven.',
imageId: 'rTqKo46'
@@ -1146,9 +1146,9 @@ export function getImageUrl(place) {
```css
ul { list-style-type: none; padding: 0px 10px; }
li {
margin-bottom: 10px;
display: grid;
li {
margin-bottom: 10px;
display: grid;
grid-template-columns: auto 1fr;
gap: 20px;
align-items: center;

View File

@@ -126,21 +126,21 @@ export default function Profile() {
<div>
<Avatar
size={100}
person={{
name: 'Katsuko Saruhashi',
person={{
name: 'Katsuko Saruhashi',
imageId: 'YfeOqp2'
}}
/>
<Avatar
size={80}
person={{
name: 'Aklilu Lemma',
name: 'Aklilu Lemma',
imageId: 'OKS67lh'
}}
/>
<Avatar
size={50}
person={{
person={{
name: 'Lin Lanying',
imageId: '1bX5QH6'
}}
@@ -291,7 +291,7 @@ export default function Profile() {
<Card>
<Avatar
size={100}
person={{
person={{
name: 'Katsuko Saruhashi',
imageId: 'YfeOqp2'
}}
@@ -453,11 +453,11 @@ export default function Gallery() {
/>
<ul>
<li>
<b>Profession: </b>
<b>Profession: </b>
physicist and chemist
</li>
<li>
<b>Awards: 4 </b>
<b>Awards: 4 </b>
(Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal, Matteucci Medal)
</li>
<li>
@@ -477,11 +477,11 @@ export default function Gallery() {
/>
<ul>
<li>
<b>Profession: </b>
<b>Profession: </b>
geochemist
</li>
<li>
<b>Awards: 2 </b>
<b>Awards: 2 </b>
(Miyake Prize for geochemistry, Tanaka Prize)
</li>
<li>
@@ -758,8 +758,8 @@ export default function Profile() {
return (
<Avatar
size={40}
person={{
name: 'Gregorio Y. Zara',
person={{
name: 'Gregorio Y. Zara',
imageId: '7vQD0fP'
}}
/>
@@ -814,15 +814,15 @@ export default function Profile() {
<>
<Avatar
size={40}
person={{
name: 'Gregorio Y. Zara',
person={{
name: 'Gregorio Y. Zara',
imageId: '7vQD0fP'
}}
/>
<Avatar
size={120}
person={{
name: 'Gregorio Y. Zara',
person={{
name: 'Gregorio Y. Zara',
imageId: '7vQD0fP'
}}
/>
@@ -878,22 +878,22 @@ export default function Profile() {
<>
<Avatar
size={40}
person={{
name: 'Gregorio Y. Zara',
person={{
name: 'Gregorio Y. Zara',
imageId: '7vQD0fP'
}}
/>
<Avatar
size={70}
person={{
name: 'Gregorio Y. Zara',
person={{
name: 'Gregorio Y. Zara',
imageId: '7vQD0fP'
}}
/>
<Avatar
size={120}
person={{
name: 'Gregorio Y. Zara',
person={{
name: 'Gregorio Y. Zara',
imageId: '7vQD0fP'
}}
/>

View File

@@ -86,7 +86,7 @@ label {
</Sandpack>
Here's how these look as a tree:
Here's how these look as a tree:
<DiagramGroup>
@@ -186,7 +186,7 @@ export default function App() {
return (
<div>
<Counter />
{showB && <Counter />}
{showB && <Counter />}
<label>
<input
type="checkbox"
@@ -288,9 +288,9 @@ export default function App() {
return (
<div>
{isFancy ? (
<Counter isFancy={true} />
<Counter isFancy={true} />
) : (
<Counter isFancy={false} />
<Counter isFancy={false} />
)}
<label>
<input
@@ -496,9 +496,9 @@ export default function App() {
return (
<div>
{isPaused ? (
<p>See you later!</p>
<p>See you later!</p>
) : (
<Counter />
<Counter />
)}
<label>
<input
@@ -596,7 +596,7 @@ export default function App() {
<div>
{isFancy ? (
<div>
<Counter isFancy={true} />
<Counter isFancy={true} />
</div>
) : (
<section>
@@ -1431,7 +1431,7 @@ export default function App() {
if (reverse) {
return (
<>
<Field label="Last name" />
<Field label="Last name" />
<Field label="First name" />
{checkbox}
</>
@@ -1439,11 +1439,11 @@ export default function App() {
} else {
return (
<>
<Field label="First name" />
<Field label="First name" />
<Field label="Last name" />
{checkbox}
</>
);
);
}
}
@@ -1493,7 +1493,7 @@ export default function App() {
if (reverse) {
return (
<>
<Field key="lastName" label="Last name" />
<Field key="lastName" label="Last name" />
<Field key="firstName" label="First name" />
{checkbox}
</>
@@ -1501,11 +1501,11 @@ export default function App() {
} else {
return (
<>
<Field key="firstName" label="First name" />
<Field key="firstName" label="First name" />
<Field key="lastName" label="Last name" />
{checkbox}
</>
);
);
}
}

View File

@@ -177,7 +177,7 @@ During the next render, React goes through the state queue:
| "replace with `5`" | `0` (unused) | `5` |
| `n => n + 1` | `5` | `5 + 1 = 6` |
React stores `6` as the final result and returns it from `useState`.
React stores `6` as the final result and returns it from `useState`.
<Note>
@@ -305,7 +305,7 @@ export default function RequestTracker() {
Completed: {completed}
</h3>
<button onClick={handleClick}>
Buy
Buy
</button>
</>
);
@@ -349,7 +349,7 @@ export default function RequestTracker() {
Completed: {completed}
</h3>
<button onClick={handleClick}>
Buy
Buy
</button>
</>
);

View File

@@ -34,7 +34,7 @@ const ref = useRef(0);
`useRef` returns an object like this:
```js
{
{
current: 0 // The value you passed to useRef
}
```

View File

@@ -411,7 +411,7 @@ function Form() {
function handleSubmit() {
setSubmitted(true);
}
}
// ...
}
@@ -429,7 +429,7 @@ function Form() {
// ✅ Good: Event-specific logic is called from event handlers
post('/api/register');
showNotification('Successfully registered!', theme);
}
}
// ...
}
@@ -884,7 +884,7 @@ const options2 = { serverUrl: 'https://localhost:1234', roomId: 'music' };
console.log(Object.is(options1, options2)); // false
```
**Object and function dependencies can make your Effect re-synchronize more often than you need.**
**Object and function dependencies can make your Effect re-synchronize more often than you need.**
This is why, whenever possible, you should try to avoid objects and functions as your Effect's dependencies. Instead, try moving them outside the component, inside the Effect, or extracting primitive values out of them.

View File

@@ -124,7 +124,7 @@ img { margin: 0 10px 10px 0; }
</Sandpack>
* **During the initial render,** React will [create the DOM nodes](https://developer.mozilla.org/docs/Web/API/Document/createElement) for `<section>`, `<h1>`, and three `<img>` tags.
* **During the initial render,** React will [create the DOM nodes](https://developer.mozilla.org/docs/Web/API/Document/createElement) for `<section>`, `<h1>`, and three `<img>` tags.
* **During a re-render,** React will calculate which of their properties, if any, have changed since the previous render. It won't do anything with that information until the next step, the commit phase.
<Pitfall>
@@ -148,9 +148,9 @@ The default behavior of rendering all components nested within the updated compo
## Step 3: React commits changes to the DOM {/*step-3-react-commits-changes-to-the-dom*/}
After rendering (calling) your components, React will modify the DOM.
After rendering (calling) your components, React will modify the DOM.
* **For the initial render,** React will use the [`appendChild()`](https://developer.mozilla.org/docs/Web/API/Node/appendChild) DOM API to put all the DOM nodes it has created on screen.
* **For the initial render,** React will use the [`appendChild()`](https://developer.mozilla.org/docs/Web/API/Node/appendChild) DOM API to put all the DOM nodes it has created on screen.
* **For re-renders,** React will apply the minimal necessary operations (calculated while rendering!) to make the DOM match the latest rendering output.
**React only changes the DOM nodes if there's a difference between renders.** For example, here is a component that re-renders with different props passed from its parent every second. Notice how you can add some text into the `<input>`, updating its `value`, but the text doesn't disappear when the component re-renders:

View File

@@ -114,7 +114,7 @@ const people = [{
profession: 'physicist',
}, {
name: 'Percy Lavon Julian',
profession: 'chemist',
profession: 'chemist',
}, {
name: 'Subrahmanyan Chandrasekhar',
profession: 'astrophysicist',
@@ -230,9 +230,9 @@ export function getImageUrl(person) {
```css
ul { list-style-type: none; padding: 0px 10px; }
li {
margin-bottom: 10px;
display: grid;
li {
margin-bottom: 10px;
display: grid;
grid-template-columns: auto 1fr;
gap: 20px;
align-items: center;
@@ -360,9 +360,9 @@ export function getImageUrl(person) {
```css
ul { list-style-type: none; padding: 0px 10px; }
li {
margin-bottom: 10px;
display: grid;
li {
margin-bottom: 10px;
display: grid;
grid-template-columns: auto 1fr;
gap: 20px;
align-items: center;

View File

@@ -169,7 +169,7 @@ This lets these two buttons show different messages. Try changing the messages p
### Passing event handlers as props {/*passing-event-handlers-as-props*/}
Often you'll want the parent component to specify a child's event handler. Consider buttons: depending on where you're using a `Button` component, you might want to execute a different function—perhaps one plays a movie and another uploads an image.
Often you'll want the parent component to specify a child's event handler. Consider buttons: depending on where you're using a `Button` component, you might want to execute a different function—perhaps one plays a movie and another uploads an image.
To do this, pass a prop the component receives from its parent as the event handler like so:
@@ -313,11 +313,11 @@ button { margin-right: 10px; }
</Sandpack>
Notice how the `App` component does not need to know *what* `Toolbar` will do with `onPlayMovie` or `onUploadImage`. That's an implementation detail of the `Toolbar`. Here, `Toolbar` passes them down as `onClick` handlers to its `Button`s, but it could later also trigger them on a keyboard shortcut. Naming props after app-specific interactions like `onPlayMovie` gives you the flexibility to change how they're used later.
<Note>
Make sure that you use the appropriate HTML tags for your event handlers. For example, to handle clicks, use [`<button onClick={handleClick}>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button) instead of `<div onClick={handleClick}>`. Using a real browser `<button>` enables built-in browser behaviors like keyboard navigation. If you don't like the default browser styling of a button and want to make it look more like a link or a different UI element, you can achieve it with CSS. [Learn more about writing accessible markup.](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML)
</Note>
## Event propagation {/*event-propagation*/}
@@ -411,7 +411,7 @@ button { margin: 5px; }
When you click on a button:
1. React calls the `onClick` handler passed to `<button>`.
1. React calls the `onClick` handler passed to `<button>`.
2. That handler, defined in `Button`, does the following:
* Calls `e.stopPropagation()`, preventing the event from bubbling further.
* Calls the `onClick` function, which is a prop passed from the `Toolbar` component.
@@ -433,10 +433,10 @@ In rare cases, you might need to catch all events on child elements, *even if th
</div>
```
Each event propagates in three phases:
Each event propagates in three phases:
1. It travels down, calling all `onClickCapture` handlers.
2. It runs the clicked element's `onClick` handler.
2. It runs the clicked element's `onClick` handler.
3. It travels upwards, calling all `onClick` handlers.
Capture events are useful for code like routers or analytics, but you probably won't use them in app code.

View File

@@ -801,7 +801,7 @@ export default function AddTask() {
type: 'added',
id: nextId++,
text: text,
});
});
}}>Add</button>
</>
);
@@ -1025,7 +1025,7 @@ export default function AddTask() {
type: 'added',
id: nextId++,
text: text,
});
});
}}>Add</button>
</>
);
@@ -1244,7 +1244,7 @@ export default function AddTask() {
type: 'added',
id: nextId++,
text: text,
});
});
}}>Add</button>
</>
);

View File

@@ -323,7 +323,7 @@ To see what this feels like in practice with a few more components, read [Thinki
#### Synced inputs {/*synced-inputs*/}
These two inputs are independent. Make them stay in sync: editing one input should update the other input with the same text, and vice versa.
These two inputs are independent. Make them stay in sync: editing one input should update the other input with the same text, and vice versa.
<Hint>
@@ -571,7 +571,7 @@ function SearchBar({ query, onChange }) {
function List({ items }) {
return (
<table>
<tbody>
<tbody>
{items.map(food => (
<tr key={food.id}>
<td>{food.name}</td>

View File

@@ -40,14 +40,14 @@ export default function Gallery() {
Next
</button>
<h2>
<i>{sculpture.name} </i>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
<h3>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<img
src={sculpture.url}
<img
src={sculpture.url}
alt={sculpture.alt}
/>
<p>
@@ -64,7 +64,7 @@ export const sculptureList = [{
artist: 'Marta Colvin Andrade',
description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.',
url: 'https://i.imgur.com/Mx7dA2Y.jpg',
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
}, {
name: 'Floralis Genérica',
artist: 'Eduardo Catalano',
@@ -220,14 +220,14 @@ export default function Gallery() {
Next
</button>
<h2>
<i>{sculpture.name} </i>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
<h3>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<img
src={sculpture.url}
<img
src={sculpture.url}
alt={sculpture.alt}
/>
<p>
@@ -244,7 +244,7 @@ export const sculptureList = [{
artist: 'Marta Colvin Andrade',
description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.',
url: 'https://i.imgur.com/Mx7dA2Y.jpg',
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
}, {
name: 'Floralis Genérica',
artist: 'Eduardo Catalano',
@@ -361,7 +361,7 @@ The convention is to name this pair like `const [something, setSomething]`. You
</Note>
The only argument to `useState` is the **initial value** of your state variable. In this example, the `index`'s initial value is set to `0` with `useState(0)`.
The only argument to `useState` is the **initial value** of your state variable. In this example, the `index`'s initial value is set to `0` with `useState(0)`.
Every time your component renders, `useState` gives you an array containing two values:
@@ -408,18 +408,18 @@ export default function Gallery() {
Next
</button>
<h2>
<i>{sculpture.name} </i>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
<h3>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<button onClick={handleMoreClick}>
{showMore ? 'Hide' : 'Show'} details
</button>
{showMore && <p>{sculpture.description}</p>}
<img
src={sculpture.url}
<img
src={sculpture.url}
alt={sculpture.alt}
/>
</>
@@ -433,7 +433,7 @@ export const sculptureList = [{
artist: 'Marta Colvin Andrade',
description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.',
url: 'https://i.imgur.com/Mx7dA2Y.jpg',
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
}, {
name: 'Floralis Genérica',
artist: 'Eduardo Catalano',
@@ -629,7 +629,7 @@ let sculptureList = [{
artist: 'Marta Colvin Andrade',
description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.',
url: 'https://i.imgur.com/Mx7dA2Y.jpg',
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
}, {
name: 'Floralis Genérica',
artist: 'Eduardo Catalano',
@@ -773,18 +773,18 @@ export default function Gallery() {
Next
</button>
<h2>
<i>{sculpture.name} </i>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
<h3>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<button onClick={handleMoreClick}>
{showMore ? 'Hide' : 'Show'} details
</button>
{showMore && <p>{sculpture.description}</p>}
<img
src={sculpture.url}
<img
src={sculpture.url}
alt={sculpture.alt}
/>
</section>
@@ -798,7 +798,7 @@ export const sculptureList = [{
artist: 'Marta Colvin Andrade',
description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.',
url: 'https://i.imgur.com/Mx7dA2Y.jpg',
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
}, {
name: 'Floralis Genérica',
artist: 'Eduardo Catalano',
@@ -944,18 +944,18 @@ export default function Gallery() {
Next
</button>
<h2>
<i>{sculpture.name} </i>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
<h3>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<button onClick={handleMoreClick}>
{showMore ? 'Hide' : 'Show'} details
</button>
{showMore && <p>{sculpture.description}</p>}
<img
src={sculpture.url}
<img
src={sculpture.url}
alt={sculpture.alt}
/>
</>
@@ -969,7 +969,7 @@ export const sculptureList = [{
artist: 'Marta Colvin Andrade',
description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.',
url: 'https://i.imgur.com/Mx7dA2Y.jpg',
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
}, {
name: 'Floralis Genérica',
artist: 'Eduardo Catalano',
@@ -1106,18 +1106,18 @@ export default function Gallery() {
Next
</button>
<h2>
<i>{sculpture.name} </i>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
<h3>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<button onClick={handleMoreClick}>
{showMore ? 'Hide' : 'Show'} details
</button>
{showMore && <p>{sculpture.description}</p>}
<img
src={sculpture.url}
<img
src={sculpture.url}
alt={sculpture.alt}
/>
</>
@@ -1131,7 +1131,7 @@ export const sculptureList = [{
artist: 'Marta Colvin Andrade',
description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.',
url: 'https://i.imgur.com/Mx7dA2Y.jpg',
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'
}, {
name: 'Floralis Genérica',
artist: 'Eduardo Catalano',
@@ -1266,7 +1266,7 @@ export default function Form() {
}
```
```css
```css
h1 { margin-top: 10px; }
```
@@ -1317,7 +1317,7 @@ export default function Form() {
}
```
```css
```css
h1 { margin-top: 10px; }
```
@@ -1446,7 +1446,7 @@ export default function FeedbackForm() {
Try moving the second `useState` call after the `if` condition and notice how this breaks it again.
If your linter is [configured for React](/learn/editor-setup#linting), you should see a lint error when you make a mistake like this. If you don't see an error when you try the faulty code locally, you need to set up linting for your project.
If your linter is [configured for React](/learn/editor-setup#linting), you should see a lint error when you make a mistake like this. If you don't see an error when you try the faulty code locally, you need to set up linting for your project.
</Solution>

View File

@@ -978,7 +978,7 @@ export default function MyInput({ value, onChange }) {
const ref = useRef(null);
// TODO: This doesn't quite work. Fix it.
// ref.current.focus()
// ref.current.focus()
return (
<input

View File

@@ -37,7 +37,7 @@ Start by drawing boxes around every component and subcomponent in the mockup and
Depending on your background, you can think about splitting up a design into components in different ways:
* **Programming**--use the same techniques for deciding if you should create a new function or object. One such technique is the [single responsibility principle](https://en.wikipedia.org/wiki/Single_responsibility_principle), that is, a component should ideally only do one thing. If it ends up growing, it should be decomposed into smaller subcomponents.
* **Programming**--use the same techniques for deciding if you should create a new function or object. One such technique is the [single responsibility principle](https://en.wikipedia.org/wiki/Single_responsibility_principle), that is, a component should ideally only do one thing. If it ends up growing, it should be decomposed into smaller subcomponents.
* **CSS**--consider what you would make class selectors for. (However, components are a bit less granular.)
* **Design**--consider how you would organize the design's layers.
@@ -228,7 +228,7 @@ What's left is probably state.
Let's go through them one by one again:
1. The original list of products is **passed in as props, so it's not state.**
1. The original list of products is **passed in as props, so it's not state.**
2. The search text seems to be state since it changes over time and can't be computed from anything.
3. The value of the checkbox seems to be state since it changes over time and can't be computed from anything.
4. The filtered list of products **isn't state because it can be computed** by taking the original list of products and filtering it according to the search text and value of the checkbox.
@@ -266,29 +266,29 @@ In the previous step, you found two pieces of state in this application: the sea
Now let's run through our strategy for them:
1. **Identify components that use state:**
* `ProductTable` needs to filter the product list based on that state (search text and checkbox value).
* `ProductTable` needs to filter the product list based on that state (search text and checkbox value).
* `SearchBar` needs to display that state (search text and checkbox value).
1. **Find their common parent:** The first parent component both components share is `FilterableProductTable`.
2. **Decide where the state lives**: We'll keep the filter text and checked state values in `FilterableProductTable`.
So the state values will live in `FilterableProductTable`.
So the state values will live in `FilterableProductTable`.
Add state to the component with the [`useState()` Hook.](/reference/react/useState) Hooks are special functions that let you "hook into" React. Add two state variables at the top of `FilterableProductTable` and specify their initial state:
```js
function FilterableProductTable({ products }) {
const [filterText, setFilterText] = useState('');
const [inStockOnly, setInStockOnly] = useState(false);
const [inStockOnly, setInStockOnly] = useState(false);
```
Then, pass `filterText` and `inStockOnly` to `ProductTable` and `SearchBar` as props:
```js
<div>
<SearchBar
filterText={filterText}
<SearchBar
filterText={filterText}
inStockOnly={inStockOnly} />
<ProductTable
<ProductTable
products={products}
filterText={filterText}
inStockOnly={inStockOnly} />
@@ -308,10 +308,10 @@ function FilterableProductTable({ products }) {
return (
<div>
<SearchBar
filterText={filterText}
<SearchBar
filterText={filterText}
inStockOnly={inStockOnly} />
<ProductTable
<ProductTable
products={products}
filterText={filterText}
inStockOnly={inStockOnly} />
@@ -389,13 +389,13 @@ function ProductTable({ products, filterText, inStockOnly }) {
function SearchBar({ filterText, inStockOnly }) {
return (
<form>
<input
type="text"
value={filterText}
<input
type="text"
value={filterText}
placeholder="Search..."/>
<label>
<input
type="checkbox"
<input
type="checkbox"
checked={inStockOnly} />
{' '}
Only show products in stock
@@ -451,9 +451,9 @@ In the sandbox above, `ProductTable` and `SearchBar` read the `filterText` and `
function SearchBar({ filterText, inStockOnly }) {
return (
<form>
<input
type="text"
value={filterText}
<input
type="text"
value={filterText}
placeholder="Search..."/>
```
@@ -462,7 +462,7 @@ However, you haven't added any code to respond to the user actions like typing y
## Step 5: Add inverse data flow {/*step-5-add-inverse-data-flow*/}
Currently your app renders correctly with props and state flowing down the hierarchy. But to change the state according to user input, you will need to support data flowing the other way: the form components deep in the hierarchy need to update the state in `FilterableProductTable`.
Currently your app renders correctly with props and state flowing down the hierarchy. But to change the state according to user input, you will need to support data flowing the other way: the form components deep in the hierarchy need to update the state in `FilterableProductTable`.
React makes this data flow explicit, but it requires a little more typing than two-way data binding. If you try to type or check the box in the example above, you'll see that React ignores your input. This is intentional. By writing `<input value={filterText} />`, you've set the `value` prop of the `input` to always be equal to the `filterText` state passed in from `FilterableProductTable`. Since `filterText` state is never set, the input never changes.
@@ -475,8 +475,8 @@ function FilterableProductTable({ products }) {
return (
<div>
<SearchBar
filterText={filterText}
<SearchBar
filterText={filterText}
inStockOnly={inStockOnly}
onFilterTextChange={setFilterText}
onInStockOnlyChange={setInStockOnly} />
@@ -485,10 +485,10 @@ function FilterableProductTable({ products }) {
Inside the `SearchBar`, you will add the `onChange` event handlers and set the parent state from them:
```js {5}
<input
type="text"
value={filterText}
placeholder="Search..."
<input
type="text"
value={filterText}
placeholder="Search..."
onChange={(e) => onFilterTextChange(e.target.value)} />
```
@@ -505,13 +505,13 @@ function FilterableProductTable({ products }) {
return (
<div>
<SearchBar
filterText={filterText}
inStockOnly={inStockOnly}
onFilterTextChange={setFilterText}
<SearchBar
filterText={filterText}
inStockOnly={inStockOnly}
onFilterTextChange={setFilterText}
onInStockOnlyChange={setInStockOnly} />
<ProductTable
products={products}
<ProductTable
products={products}
filterText={filterText}
inStockOnly={inStockOnly} />
</div>
@@ -593,14 +593,14 @@ function SearchBar({
}) {
return (
<form>
<input
type="text"
value={filterText} placeholder="Search..."
<input
type="text"
value={filterText} placeholder="Search..."
onChange={(e) => onFilterTextChange(e.target.value)} />
<label>
<input
type="checkbox"
checked={inStockOnly}
<input
type="checkbox"
checked={inStockOnly}
onChange={(e) => onInStockOnlyChange(e.target.checked)} />
{' '}
Only show products in stock

View File

@@ -337,7 +337,7 @@ import './styles.css';
import App from './App';
```
Lines 1-5 brings all the necessary pieces together:
Lines 1-5 brings all the necessary pieces together:
* React
* React's library to talk to web browsers (React DOM)
@@ -551,7 +551,7 @@ export default function Board() {
}
```
Note how unlike the browser `div`s, your own components `Board` and `Square` must start with a capital letter.
Note how unlike the browser `div`s, your own components `Board` and `Square` must start with a capital letter.
Let's take a look:
@@ -1094,7 +1094,7 @@ function Square({ value, onSquareClick }) {
}
```
Now you'll connect the `onSquareClick` prop to a function in the `Board` component that you'll name `handleClick`. To connect `onSquareClick` to `handleClick` you'll pass a function to the `onSquareClick` prop of the first `Square` component:
Now you'll connect the `onSquareClick` prop to a function in the `Board` component that you'll name `handleClick`. To connect `onSquareClick` to `handleClick` you'll pass a function to the `onSquareClick` prop of the first `Square` component:
```js {7}
export default function Board() {
@@ -2073,12 +2073,12 @@ export default function Game() {
}
```
You can see what your code should look like below. Note that you should see an error in the developer tools console that says:
You can see what your code should look like below. Note that you should see an error in the developer tools console that says:
<ConsoleBlock level="warning">
Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of &#96;Game&#96;.
</ConsoleBlock>
You'll fix this error in the next section.
<Sandpack>

View File

@@ -124,7 +124,7 @@ The type describing your component's props can be as simple or as complex as you
## Example Hooks {/*example-hooks*/}
The type definitions from `@types/react` include types for the built-in hooks, so you can use them in your components without any additional setup. They are built to take into account the code you write in your component, so you will get [inferred types](https://www.typescriptlang.org/docs/handbook/type-inference.html) a lot of the time and ideally do not need to handle the minutiae of providing the types.
The type definitions from `@types/react` include types for the built-in hooks, so you can use them in your components without any additional setup. They are built to take into account the code you write in your component, so you will get [inferred types](https://www.typescriptlang.org/docs/handbook/type-inference.html) a lot of the time and ideally do not need to handle the minutiae of providing the types.
However, we can look at a few examples of how to provide types for hooks.
@@ -139,7 +139,7 @@ const [enabled, setEnabled] = useState(false);
Will assign the type of `boolean` to `enabled`, and `setEnabled` will be a function accepting either a `boolean` argument, or a function that returns a `boolean`. If you want to explicitly provide a type for the state, you can do so by providing a type argument to the `useState` call:
```ts
```ts
// Explicitly set the type to "boolean"
const [enabled, setEnabled] = useState<boolean>(false);
```
@@ -174,7 +174,7 @@ The [`useReducer` hook](/reference/react/useReducer) is a more complex hook that
import {useReducer} from 'react';
interface State {
count: number
count: number
};
type CounterAction =
@@ -284,7 +284,7 @@ export default App = AppTSX;
</Sandpack>
This technique works when you have a default value which makes sense - but there are occasionally cases when you do not, and in those cases `null` can feel reasonable as a default value. However, to allow the type-system to understand your code, you need to explicitly set `ContextShape | null` on the `createContext`.
This technique works when you have a default value which makes sense - but there are occasionally cases when you do not, and in those cases `null` can feel reasonable as a default value. However, to allow the type-system to understand your code, you need to explicitly set `ContextShape | null` on the `createContext`.
This causes the issue that you need to eliminate the `| null` in the type for context consumers. Our recommendation is to have the hook do a runtime check for it's existence and throw an error when not present:
@@ -350,7 +350,7 @@ const handleClick = useCallback(() => {
When working in TypeScript strict mode `useCallback` requires adding types for the parameters in your callback. This is because the type of the callback is inferred from the return value of the function, and without parameters the type cannot be fully understood.
Depending on your code-style preferences, you could use the `*EventHandler` functions from the React types to provide the type for the event handler at the same time as defining the callback:
Depending on your code-style preferences, you could use the `*EventHandler` functions from the React types to provide the type for the event handler at the same time as defining the callback:
```ts
import { useState, useCallback } from 'react';
@@ -361,7 +361,7 @@ export default function Form() {
const handleChange = useCallback<React.ChangeEventHandler<HTMLInputElement>>((event) => {
setValue(event.currentTarget.value);
}, [setValue])
return (
<>
<input value={value} onChange={handleChange} />
@@ -433,7 +433,7 @@ interface ModalRendererProps {
}
```
Note, that you cannot use TypeScript to describe that the children are a certain type of JSX elements, so you cannot use the type-system to describe a component which only accepts `<li>` children.
Note, that you cannot use TypeScript to describe that the children are a certain type of JSX elements, so you cannot use the type-system to describe a component which only accepts `<li>` children.
You can see all an example of both `React.ReactNode` and `React.ReactElement` with the type-checker in [this TypeScript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wChSB6CxYmAOmXRgDkIATJOdNJMGAZzgwAFpxAR+8YADswAVwGkZMJFEzpOjDKw4AFHGEEBvUnDhphwADZsi0gFw0mDWjqQBuUgF9yaCNMlENzgAXjgACjADfkctFnYkfQhDAEpQgD44AB42YAA3dKMo5P46C2tbJGkvLIpcgt9-QLi3AEEwMFCItJDMrPTTbIQ3dKywdIB5aU4kKyQQKpha8drhhIGzLLWODbNs3b3s8YAxKBQAcwXpAThMaGWDvbH0gFloGbmrgQfBzYpd1YjQZbEYARkB6zMwO2SHSAAlZlYIBCdtCRkZpHIrFYahQYQD8UYYFA5EhcfjyGYqHAXnJAsIUHlOOUbHYhMIIHJzsI0Qk4P9SLUBuRqXEXEwAKKfRZcNA8PiCfxWACecAAUgBlAAacFm80W-CU11U6h4TgwUv11yShjgJjMLMqDnN9Dilq+nh8pD8AXgCHdMrCkWisVoAet0R6fXqhWKhjKllZVVxMcavpd4Zg7U6Qaj+2hmdG4zeRF10uu-Aeq0LBfLMEe-V+T2L7zLVu+FBWLdLeq+lc7DYFf39deFVOotMCACNOCh1dq219a+30uC8YWoZsRyuEdjkevR8uvoVMdjyTWt4WiSSydXD4NqZP4AymeZE072ZzuUeZQKheQgA).

View File

@@ -197,7 +197,7 @@ setPosition({
Mutation is only a problem when you change *existing* objects that are already in state. Mutating an object you've just created is okay because *no other code references it yet.* Changing it isn't going to accidentally impact something that depends on it. This is called a "local mutation". You can even do local mutation [while rendering.](/learn/keeping-components-pure#local-mutation-your-components-little-secret) Very convenient and completely okay!
</DeepDive>
</DeepDive>
## Copying objects with the spread syntax {/*copying-objects-with-the-spread-syntax*/}
@@ -294,7 +294,7 @@ setPerson({
});
```
Now the form works!
Now the form works!
Notice how you didn't declare a separate state variable for each input field. For large forms, keeping all data grouped in an object is very convenient--as long as you update it correctly!
@@ -371,7 +371,7 @@ input { margin-left: 5px; margin-bottom: 5px; }
</Sandpack>
Note that the `...` spread syntax is "shallow"--it only copies things one level deep. This makes it fast, but it also means that if you want to update a nested property, you'll have to use it more than once.
Note that the `...` spread syntax is "shallow"--it only copies things one level deep. This makes it fast, but it also means that if you want to update a nested property, you'll have to use it more than once.
<DeepDive>
@@ -577,8 +577,8 @@ export default function Form() {
<br />
(located in {person.artwork.city})
</p>
<img
src={person.artwork.image}
<img
src={person.artwork.image}
alt={person.artwork.title}
/>
</>
@@ -648,7 +648,7 @@ let obj3 = {
If you were to mutate `obj3.artwork.city`, it would affect both `obj2.artwork.city` and `obj1.city`. This is because `obj3.artwork`, `obj2.artwork`, and `obj1` are the same object. This is difficult to see when you think of objects as "nested". Instead, they are separate objects "pointing" at each other with properties.
</DeepDive>
</DeepDive>
### Write concise update logic with Immer {/*write-concise-update-logic-with-immer*/}
@@ -753,8 +753,8 @@ export default function Form() {
<br />
(located in {person.artwork.city})
</p>
<img
src={person.artwork.image}
<img
src={person.artwork.image}
alt={person.artwork.title}
/>
</>

View File

@@ -70,9 +70,9 @@ Suppose that you have some (perfectly valid) HTML:
```html
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
@@ -102,9 +102,9 @@ export default function TodoList() {
return (
// This doesn't quite work!
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
@@ -141,9 +141,9 @@ For example, you can use a `<div>`:
```js {1,11}
<div>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
@@ -158,9 +158,9 @@ If you don't want to add an extra `<div>` to your markup, you can write `<>` and
```js {1,11}
<>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
@@ -187,9 +187,9 @@ This is how Hedy Lamarr's image and list items look closed:
```js {2-6,8-10}
<>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
/>
<ul>
@@ -207,9 +207,9 @@ JSX turns into JavaScript and attributes written in JSX become keys of JavaScrip
This is why, in React, many HTML and SVG attributes are written in camelCase. For example, instead of `stroke-width` you use `strokeWidth`. Since `class` is a reserved word, in React you write `className` instead, named after the [corresponding DOM property](https://developer.mozilla.org/en-US/docs/Web/API/Element/className):
```js {4}
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
className="photo"
/>
```
@@ -235,10 +235,10 @@ export default function TodoList() {
return (
<>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
className="photo"
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
className="photo"
/>
<ul>
<li>Invent new traffic lights</li>

View File

@@ -341,9 +341,9 @@ Or by wrapping the returned JSX markup in parentheses that open right after `ret
```js
export default function Profile() {
return (
<img
src="https://i.imgur.com/jA8hHMpm.jpg"
alt="Katsuko Saruhashi"
<img
src="https://i.imgur.com/jA8hHMpm.jpg"
alt="Katsuko Saruhashi"
/>
);
}

View File

@@ -102,7 +102,7 @@ An app fully built with React will usually not have any calls to `root.unmount`.
This is mostly useful if your React root's DOM node (or any of its ancestors) may get removed from the DOM by some other code. For example, imagine a jQuery tab panel that removes inactive tabs from the DOM. If a tab gets removed, everything inside it (including the React roots inside) would get removed from the DOM as well. In that case, you need to tell React to "stop" managing the removed root's content by calling `root.unmount`. Otherwise, the components inside the removed root won't know to clean up and free up global resources like subscriptions.
Calling `root.unmount` will unmount all the components in the root and "detach" React from the root DOM node, including removing any event handlers or state in the tree.
Calling `root.unmount` will unmount all the components in the root and "detach" React from the root DOM node, including removing any event handlers or state in the tree.
#### Parameters {/*root-unmount-parameters*/}
@@ -186,7 +186,7 @@ function Counter() {
</Sandpack>
**If your app is fully built with React, you shouldn't need to create any more roots, or to call [`root.render`](#root-render) again.**
**If your app is fully built with React, you shouldn't need to create any more roots, or to call [`root.render`](#root-render) again.**
From this point on, React will manage the DOM of your entire app. To add more components, [nest them inside the `App` component.](/learn/importing-and-exporting-components) When you need to update the UI, each of your components can do this by [using state.](/reference/react/useState) When you need to display extra content like a modal or a tooltip outside the DOM node, [render it with a portal.](/reference/react-dom/createPortal)
@@ -238,11 +238,11 @@ import { createRoot } from 'react-dom/client';
import { Comments, Navigation } from './Components.js';
const navDomNode = document.getElementById('navigation');
const navRoot = createRoot(navDomNode);
const navRoot = createRoot(navDomNode);
navRoot.render(<Navigation />);
const commentDomNode = document.getElementById('comments');
const commentRoot = createRoot(commentDomNode);
const commentRoot = createRoot(commentDomNode);
commentRoot.render(<Comments />);
```
@@ -292,7 +292,7 @@ You could also create a new DOM node with [`document.createElement()`](https://d
```js
const domNode = document.createElement('div');
const root = createRoot(domNode);
const root = createRoot(domNode);
root.render(<Comment />);
document.body.appendChild(domNode); // You can add it anywhere in the document
```

View File

@@ -97,7 +97,7 @@ An app fully built with React will usually not have any calls to `root.unmount`.
This is mostly useful if your React root's DOM node (or any of its ancestors) may get removed from the DOM by some other code. For example, imagine a jQuery tab panel that removes inactive tabs from the DOM. If a tab gets removed, everything inside it (including the React roots inside) would get removed from the DOM as well. You need to tell React to "stop" managing the removed root's content by calling `root.unmount`. Otherwise, the components inside the removed root won't clean up and free up resources like subscriptions.
Calling `root.unmount` will unmount all the components in the root and "detach" React from the root DOM node, including removing any event handlers or state in the tree.
Calling `root.unmount` will unmount all the components in the root and "detach" React from the root DOM node, including removing any event handlers or state in the tree.
#### Parameters {/*root-unmount-parameters*/}

View File

@@ -84,11 +84,11 @@ These standard DOM props are also supported for all built-in components:
* `onCutCapture`: A version of `onCut` that fires in the [capture phase.](/learn/responding-to-events#capture-phase-events)
* `onDoubleClick`: A [`MouseEvent` handler](#mouseevent-handler) function. Fires when the user clicks twice. Corresponds to the browser [`dblclick` event.](https://developer.mozilla.org/en-US/docs/Web/API/Element/dblclick_event)
* `onDoubleClickCapture`: A version of `onDoubleClick` that fires in the [capture phase.](/learn/responding-to-events#capture-phase-events)
* [`onDrag`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/drag_event): A [`DragEvent` handler](#dragevent-handler) function. Fires while the user is dragging something.
* [`onDrag`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/drag_event): A [`DragEvent` handler](#dragevent-handler) function. Fires while the user is dragging something.
* `onDragCapture`: A version of `onDrag` that fires in the [capture phase.](/learn/responding-to-events#capture-phase-events)
* [`onDragEnd`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragend_event): A [`DragEvent` handler](#dragevent-handler) function. Fires when the user stops dragging something.
* [`onDragEnd`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragend_event): A [`DragEvent` handler](#dragevent-handler) function. Fires when the user stops dragging something.
* `onDragEndCapture`: A version of `onDragEnd` that fires in the [capture phase.](/learn/responding-to-events#capture-phase-events)
* [`onDragEnter`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragenter_event): A [`DragEvent` handler](#dragevent-handler) function. Fires when the dragged content enters a valid drop target.
* [`onDragEnter`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragenter_event): A [`DragEvent` handler](#dragevent-handler) function. Fires when the dragged content enters a valid drop target.
* `onDragEnterCapture`: A version of `onDragEnter` that fires in the [capture phase.](/learn/responding-to-events#capture-phase-events)
* [`onDragOver`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragover_event): A [`DragEvent` handler](#dragevent-handler) function. Fires on a valid drop target while the dragged content is dragged over it. You must call `e.preventDefault()` here to allow dropping.
* `onDragOverCapture`: A version of `onDragOver` that fires in the [capture phase.](/learn/responding-to-events#capture-phase-events)
@@ -283,7 +283,7 @@ Some React events do not map directly to the browser's native events. For exampl
React event objects implement some of the standard [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event) properties:
* [`bubbles`](https://developer.mozilla.org/en-US/docs/Web/API/Event/bubbles): A boolean. Returns whether the event bubbles through the DOM.
* [`bubbles`](https://developer.mozilla.org/en-US/docs/Web/API/Event/bubbles): A boolean. Returns whether the event bubbles through the DOM.
* [`cancelable`](https://developer.mozilla.org/en-US/docs/Web/API/Event/cancelable): A boolean. Returns whether the event can be canceled.
* [`currentTarget`](https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget): A DOM node. Returns the node to which the current handler is attached in the React tree.
* [`defaultPrevented`](https://developer.mozilla.org/en-US/docs/Web/API/Event/defaultPrevented): A boolean. Returns whether `preventDefault` was called.
@@ -643,7 +643,7 @@ An event handler type for [touch events.](https://developer.mozilla.org/en-US/do
* [`shiftKey`](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/shiftKey)
* [`touches`](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/touches)
* [`targetTouches`](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/targetTouches)
It also includes the inherited [`UIEvent`](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent) properties:
* [`detail`](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail)

View File

@@ -210,7 +210,7 @@ export default function MyForm() {
type="radio"
name="myRadio"
value="option2"
defaultChecked={true}
defaultChecked={true}
/>
Option 2
</label>

View File

@@ -79,5 +79,5 @@ export default function FruitPicker() {
select { margin: 5px; }
```
</Sandpack>
</Sandpack>

View File

@@ -103,7 +103,7 @@ export default function FruitPicker() {
select { margin: 5px; }
```
</Sandpack>
</Sandpack>
---
@@ -178,7 +178,7 @@ export default function FruitPicker() {
select { margin: 5px; }
```
</Sandpack>
</Sandpack>
<Pitfall>

View File

@@ -47,7 +47,7 @@ export default App() {
}
```
To get status information, the `Submit` component must be rendered within a `<form>`. The Hook returns information like the <CodeStep step={1}>`pending`</CodeStep> property which tells you if the form is actively submitting.
To get status information, the `Submit` component must be rendered within a `<form>`. The Hook returns information like the <CodeStep step={1}>`pending`</CodeStep> property which tells you if the form is actively submitting.
In the above example, `Submit` uses this information to disable `<button>` presses while the form is submitting.
@@ -72,7 +72,7 @@ A `status` object with the following properties:
#### Caveats {/*caveats*/}
* The `useFormStatus` Hook must be called from a component that is rendered inside a `<form>`.
* The `useFormStatus` Hook must be called from a component that is rendered inside a `<form>`.
* `useFormStatus` will only return status information for a parent `<form>`. It will not return status information for any `<form>` rendered in that same component or children components.
---
@@ -82,7 +82,7 @@ A `status` object with the following properties:
### Display a pending state during form submission {/*display-a-pending-state-during-form-submission*/}
To display a pending state while a form is submitting, you can call the `useFormStatus` Hook in a component rendered in a `<form>` and read the `pending` property returned.
Here, we use the `pending` property to indicate the form is submitting.
Here, we use the `pending` property to indicate the form is submitting.
<Sandpack>
@@ -129,7 +129,7 @@ export async function submitForm(query) {
"devDependencies": {}
}
```
</Sandpack>
</Sandpack>
<Pitfall>
@@ -151,7 +151,7 @@ Instead call `useFormStatus` from inside a component that is located inside `<fo
```js
function Submit() {
// ✅ `pending` will be derived from the form that wraps the Submit component
const { pending } = useFormStatus();
const { pending } = useFormStatus();
return <button disabled={pending}>...</button>;
}
@@ -246,7 +246,7 @@ export async function submitForm(query) {
"devDependencies": {}
}
```
</Sandpack>
</Sandpack>
---
@@ -254,7 +254,7 @@ export async function submitForm(query) {
### `status.pending` is never `true` {/*pending-is-never-true*/}
`useFormStatus` will only return status information for a parent `<form>`.
`useFormStatus` will only return status information for a parent `<form>`.
If the component that calls `useFormStatus` is not nested in a `<form>`, `status.pending` will always return `false`. Verify `useFormStatus` is called in a component that is a child of a `<form>` element.

View File

@@ -45,7 +45,7 @@ An app fully built with React will usually only have one `render` call with its
#### Parameters {/*parameters*/}
* `reactNode`: A *React node* that you want to display. This will usually be a piece of JSX like `<App />`, but you can also pass a React element constructed with [`createElement()`](/reference/react/createElement), a string, a number, `null`, or `undefined`.
* `reactNode`: A *React node* that you want to display. This will usually be a piece of JSX like `<App />`, but you can also pass a React element constructed with [`createElement()`](/reference/react/createElement), a string, a number, `null`, or `undefined`.
* `domNode`: A [DOM element.](https://developer.mozilla.org/en-US/docs/Web/API/Element) React will display the `reactNode` you pass inside this DOM element. From this moment, React will manage the DOM inside the `domNode` and update it when your React tree changes.

View File

@@ -294,7 +294,7 @@ Suspense **does not** detect when data is fetched inside an Effect or event hand
The exact way you would load data in the `Posts` component above depends on your framework. If you use a Suspense-enabled framework, you'll find the details in its data fetching documentation.
Suspense-enabled data fetching without the use of an opinionated framework is not yet supported. The requirements for implementing a Suspense-enabled data source are unstable and undocumented. An official API for integrating data sources with Suspense will be released in a future version of React.
Suspense-enabled data fetching without the use of an opinionated framework is not yet supported. The requirements for implementing a Suspense-enabled data source are unstable and undocumented. An official API for integrating data sources with Suspense will be released in a future version of React.
</Note>
@@ -401,7 +401,7 @@ const { pipe } = renderToPipeableStream(<App />, {
onShellError(error) {
response.statusCode = 500;
response.setHeader('content-type', 'text/html');
response.send('<h1>Something went wrong</h1>');
response.send('<h1>Something went wrong</h1>');
},
onError(error) {
console.error(error);
@@ -460,7 +460,7 @@ const { pipe } = renderToPipeableStream(<App />, {
onShellError(error) {
response.statusCode = 500;
response.setHeader('content-type', 'text/html');
response.send('<h1>Something went wrong</h1>');
response.send('<h1>Something went wrong</h1>');
},
onError(error) {
console.error(error);
@@ -486,7 +486,7 @@ const { pipe } = renderToPipeableStream(<App />, {
onShellError(error) {
response.statusCode = 500;
response.setHeader('content-type', 'text/html');
response.send('<h1>Something went wrong</h1>');
response.send('<h1>Something went wrong</h1>');
},
onError(error) {
didError = true;
@@ -530,7 +530,7 @@ const { pipe } = renderToPipeableStream(<App />, {
onShellError(error) {
response.statusCode = getStatusCode();
response.setHeader('content-type', 'text/html');
response.send('<h1>Something went wrong</h1>');
response.send('<h1>Something went wrong</h1>');
},
onError(error) {
didError = true;
@@ -570,13 +570,13 @@ const { pipe } = renderToPipeableStream(<App />, {
onShellError(error) {
response.statusCode = 500;
response.setHeader('content-type', 'text/html');
response.send('<h1>Something went wrong</h1>');
response.send('<h1>Something went wrong</h1>');
},
onAllReady() {
if (isCrawler) {
response.statusCode = didError ? 500 : 200;
response.setHeader('content-type', 'text/html');
pipe(response);
pipe(response);
}
},
onError(error) {

View File

@@ -293,7 +293,7 @@ Suspense **does not** detect when data is fetched inside an Effect or event hand
The exact way you would load data in the `Posts` component above depends on your framework. If you use a Suspense-enabled framework, you'll find the details in its data fetching documentation.
Suspense-enabled data fetching without the use of an opinionated framework is not yet supported. The requirements for implementing a Suspense-enabled data source are unstable and undocumented. An official API for integrating data sources with Suspense will be released in a future version of React.
Suspense-enabled data fetching without the use of an opinionated framework is not yet supported. The requirements for implementing a Suspense-enabled data source are unstable and undocumented. An official API for integrating data sources with Suspense will be released in a future version of React.
</Note>

View File

@@ -492,7 +492,7 @@ As mentioned earlier, there is no way to get the rendered output of an inner com
### Converting children to an array {/*converting-children-to-an-array*/}
Call `Children.toArray(children)` to turn the `children` data structure into a regular JavaScript array. This lets you manipulate the array with built-in array methods like [`filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), [`sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort), or [`reverse`.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse)
Call `Children.toArray(children)` to turn the `children` data structure into a regular JavaScript array. This lets you manipulate the array with built-in array methods like [`filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), [`sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort), or [`reverse`.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse)
<Sandpack>
@@ -861,7 +861,7 @@ export default function App() {
return (
<Row isHighlighted={index % 2 === 0}>
<p>This is the {id} item.</p>
</Row>
</Row>
);
}}
/>

View File

@@ -129,7 +129,7 @@ class Counter extends Component {
handleAgeChange = () => {
this.setState({
age: this.state.age + 1
age: this.state.age + 1
});
};
@@ -748,7 +748,7 @@ Return `false` to tell React that re-rendering can be skipped.
#### Caveats {/*shouldcomponentupdate-caveats*/}
- This method *only* exists as a performance optimization. If your component breaks without it, fix that first.
- This method *only* exists as a performance optimization. If your component breaks without it, fix that first.
- Consider using [`PureComponent`](/reference/react/PureComponent) instead of writing `shouldComponentUpdate` by hand. `PureComponent` shallowly compares props and state, and reduces the chance that you'll skip a necessary update.
@@ -1174,7 +1174,7 @@ export default class Counter extends Component {
handleAgeChange = () => {
this.setState({
age: this.state.age + 1
age: this.state.age + 1
});
};
@@ -1199,7 +1199,7 @@ export default class Counter extends Component {
button { display: block; margin-top: 10px; }
```
</Sandpack>
</Sandpack>
<Pitfall>
@@ -1283,7 +1283,7 @@ export default class ChatRoom extends Component {
this.state.serverUrl,
this.props.roomId
);
this.connection.connect();
this.connection.connect();
}
destroyConnection() {
@@ -1496,7 +1496,7 @@ export default class Counter extends Component {
handleAgeChange = (e) => {
this.setState({
age: this.state.age + 1
age: this.state.age + 1
});
};
@@ -1663,7 +1663,7 @@ export default class ChatRoom extends Component {
this.state.serverUrl,
this.props.roomId
);
this.connection.connect();
this.connection.connect();
}
destroyConnection() {
@@ -1852,7 +1852,7 @@ class Panel extends Component {
<h1>{this.props.title}</h1>
{this.props.children}
</section>
);
);
}
}

View File

@@ -214,7 +214,7 @@ li {
There is a mistake in the code above. However, it is easy to miss because the initial output appears correct.
This mistake will become more noticeable if the `StoryTray` component re-renders multiple times. For example, let's make the `StoryTray` re-render with a different background color whenever you hover over it:
This mistake will become more noticeable if the `StoryTray` component re-renders multiple times. For example, let's make the `StoryTray` re-render with a different background color whenever you hover over it:
<Sandpack>
@@ -823,7 +823,7 @@ Without Strict Mode, it was easy to miss that your Effect needed cleanup. By run
React warns if some component anywhere inside a `<StrictMode>` tree uses one of these deprecated APIs:
* [`findDOMNode`](/reference/react-dom/findDOMNode). [See alternatives.](https://reactjs.org/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage)
* `UNSAFE_` class lifecycle methods like [`UNSAFE_componentWillMount`](/reference/react/Component#unsafe_componentwillmount). [See alternatives.](https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#migrating-from-legacy-lifecycles)
* `UNSAFE_` class lifecycle methods like [`UNSAFE_componentWillMount`](/reference/react/Component#unsafe_componentwillmount). [See alternatives.](https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#migrating-from-legacy-lifecycles)
* Legacy context ([`childContextTypes`](/reference/react/Component#static-childcontexttypes), [`contextTypes`](/reference/react/Component#static-contexttypes), and [`getChildContext`](/reference/react/Component#getchildcontext)). [See alternatives.](/reference/react/createContext)
* Legacy string refs ([`this.refs`](/reference/react/Component#refs)). [See alternatives.](https://reactjs.org/docs/strict-mode.html#warning-about-legacy-string-ref-api-usage)

View File

@@ -155,7 +155,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -260,7 +260,7 @@ Suspense **does not** detect when data is fetched inside an Effect or event hand
The exact way you would load data in the `Albums` component above depends on your framework. If you use a Suspense-enabled framework, you'll find the details in its data fetching documentation.
Suspense-enabled data fetching without the use of an opinionated framework is not yet supported. The requirements for implementing a Suspense-enabled data source are unstable and undocumented. An official API for integrating data sources with Suspense will be released in a future version of React.
Suspense-enabled data fetching without the use of an opinionated framework is not yet supported. The requirements for implementing a Suspense-enabled data source are unstable and undocumented. An official API for integrating data sources with Suspense will be released in a future version of React.
</Note>
@@ -397,7 +397,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -445,7 +445,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -482,9 +482,9 @@ async function getBio() {
setTimeout(resolve, 1500);
});
return `The Beatles were an English rock band,
formed in Liverpool in 1960, that comprised
John Lennon, Paul McCartney, George Harrison
return `The Beatles were an English rock band,
formed in Liverpool in 1960, that comprised
John Lennon, Paul McCartney, George Harrison
and Ringo Starr.`;
}
@@ -734,7 +734,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -782,7 +782,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -819,9 +819,9 @@ async function getBio() {
setTimeout(resolve, 500);
});
return `The Beatles were an English rock band,
formed in Liverpool in 1960, that comprised
John Lennon, Paul McCartney, George Harrison
return `The Beatles were an English rock band,
formed in Liverpool in 1960, that comprised
John Lennon, Paul McCartney, George Harrison
and Ringo Starr.`;
}
@@ -1011,7 +1011,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -1117,7 +1117,7 @@ input { margin: 10px; }
</Sandpack>
A common alternative UI pattern is to *defer* updating the list and to keep showing the previous results until the new results are ready. The [`useDeferredValue`](/reference/react/useDeferredValue) Hook lets you pass a deferred version of the query down:
A common alternative UI pattern is to *defer* updating the list and to keep showing the previous results until the new results are ready. The [`useDeferredValue`](/reference/react/useDeferredValue) Hook lets you pass a deferred version of the query down:
```js {3,11}
export default function App() {
@@ -1143,7 +1143,7 @@ To make it more obvious to the user, you can add a visual indication when the st
```js {2}
<div style={{
opacity: query !== deferredQuery ? 0.5 : 1
opacity: query !== deferredQuery ? 0.5 : 1
}}>
<SearchResults query={deferredQuery} />
</div>
@@ -1240,7 +1240,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -1520,7 +1520,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -1564,7 +1564,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -1611,9 +1611,9 @@ async function getBio() {
setTimeout(resolve, 500);
});
return `The Beatles were an English rock band,
formed in Liverpool in 1960, that comprised
John Lennon, Paul McCartney, George Harrison
return `The Beatles were an English rock band,
formed in Liverpool in 1960, that comprised
John Lennon, Paul McCartney, George Harrison
and Ringo Starr.`;
}
@@ -1735,7 +1735,7 @@ function Router() {
function navigate(url) {
startTransition(() => {
setPage(url);
setPage(url);
});
}
// ...
@@ -1907,7 +1907,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -1951,7 +1951,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -1998,9 +1998,9 @@ async function getBio() {
setTimeout(resolve, 500);
});
return `The Beatles were an English rock band,
formed in Liverpool in 1960, that comprised
John Lennon, Paul McCartney, George Harrison
return `The Beatles were an English rock band,
formed in Liverpool in 1960, that comprised
John Lennon, Paul McCartney, George Harrison
and Ringo Starr.`;
}
@@ -2293,7 +2293,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -2337,7 +2337,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -2384,9 +2384,9 @@ async function getBio() {
setTimeout(resolve, 500);
});
return `The Beatles were an English rock band,
formed in Liverpool in 1960, that comprised
John Lennon, Paul McCartney, George Harrison
return `The Beatles were an English rock band,
formed in Liverpool in 1960, that comprised
John Lennon, Paul McCartney, George Harrison
and Ringo Starr.`;
}

View File

@@ -65,7 +65,7 @@ The optimization of caching return values based on inputs is known as [_memoizat
[//]: # 'TODO: add links to Server/Client Component reference once https://github.com/reactjs/react.dev/pull/6177 is merged'
- React will invalidate the cache for all memoized functions for each server request.
- React will invalidate the cache for all memoized functions for each server request.
- Each call to `cache` creates a new function. This means that calling `cache` with the same function multiple times will return different memoized functions that do not share the same cache.
- `cachedFn` will also cache errors. If `fn` throws an error for certain arguments, it will be cached, and the same error is re-thrown when `cachedFn` is called with those same arguments.
- `cache` is for use in [Server Components](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) only.
@@ -98,9 +98,9 @@ function TeamReport({users}) {
}
```
If the same `user` object is rendered in both `Profile` and `TeamReport`, the two components can share work and only call `calculateUserMetrics` once for that `user`.
If the same `user` object is rendered in both `Profile` and `TeamReport`, the two components can share work and only call `calculateUserMetrics` once for that `user`.
Assume `Profile` is rendered first. It will call <CodeStep step={1}>`getUserMetrics`</CodeStep>, and check if there is a cached result. Since it is the first time `getUserMetrics` is called with that `user`, there will be a cache miss. `getUserMetrics` will then call `calculateUserMetrics` with that `user` and write the result to cache.
Assume `Profile` is rendered first. It will call <CodeStep step={1}>`getUserMetrics`</CodeStep>, and check if there is a cached result. Since it is the first time `getUserMetrics` is called with that `user`, there will be a cache miss. `getUserMetrics` will then call `calculateUserMetrics` with that `user` and write the result to cache.
When `TeamReport` renders its list of `users` and reaches the same `user` object, it will call <CodeStep step={2}>`getUserMetrics`</CodeStep> and read the result from cache.
@@ -170,12 +170,12 @@ export default function Precipitation({cityData}) {
// ...
}
```
Here, both components call the <CodeStep step={3}>same memoized function</CodeStep> exported from `./getWeekReport.js` to read and write to the same cache.
Here, both components call the <CodeStep step={3}>same memoized function</CodeStep> exported from `./getWeekReport.js` to read and write to the same cache.
</Pitfall>
### Share a snapshot of data {/*take-and-share-snapshot-of-data*/}
To share a snapshot of data between components, call `cache` with a data-fetching function like `fetch`. When multiple components make the same data fetch, only one request is made and the data returned is cached and shared across components. All components refer to the same snapshot of data across the server render.
To share a snapshot of data between components, call `cache` with a data-fetching function like `fetch`. When multiple components make the same data fetch, only one request is made and the data returned is cached and shared across components. All components refer to the same snapshot of data across the server render.
```js [[1, 4, "city"], [1, 5, "fetchTemperature(city)"], [2, 4, "getTemperature"], [2, 9, "getTemperature"], [1, 9, "city"], [2, 14, "getTemperature"], [1, 14, "city"]]
import {cache} from 'react';
@@ -196,7 +196,7 @@ async function MinimalWeatherCard({city}) {
}
```
If `AnimatedWeatherCard` and `MinimalWeatherCard` both render for the same <CodeStep step={1}>city</CodeStep>, they will receive the same snapshot of data from the <CodeStep step={2}>memoized function</CodeStep>.
If `AnimatedWeatherCard` and `MinimalWeatherCard` both render for the same <CodeStep step={1}>city</CodeStep>, they will receive the same snapshot of data from the <CodeStep step={2}>memoized function</CodeStep>.
If `AnimatedWeatherCard` and `MinimalWeatherCard` supply different <CodeStep step={1}>city</CodeStep> arguments to <CodeStep step={2}>`getTemperature`</CodeStep>, then `fetchTemperature` will be called twice and each call site will receive different data.
@@ -260,7 +260,7 @@ When rendering `Profile`, we call <CodeStep step={2}>`getUser`</CodeStep> again.
When evaluating an [asynchronous function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function), you will receive a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) for that work. The promise holds the state of that work (_pending_, _fulfilled_, _failed_) and its eventual settled result.
In this example, the asynchronous function <CodeStep step={1}>`fetchData`</CodeStep> returns a promise that is awaiting the `fetch`.
In this example, the asynchronous function <CodeStep step={1}>`fetchData`</CodeStep> returns a promise that is awaiting the `fetch`.
```js [[1, 1, "fetchData()"], [2, 8, "getData()"], [3, 10, "getData()"]]
async function fetchData() {
@@ -271,7 +271,7 @@ const getData = cache(fetchData);
async function MyComponent() {
getData();
// ... some computational work
// ... some computational work
await getData();
// ...
}
@@ -281,7 +281,7 @@ In calling <CodeStep step={2}>`getData`</CodeStep> the first time, the promise r
Notice that the first <CodeStep step={2}>`getData`</CodeStep> call does not `await` whereas the <CodeStep step={3}>second</CodeStep> does. [`await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await) is a JavaScript operator that will wait and return the settled result of the promise. The first <CodeStep step={2}>`getData`</CodeStep> call simply initiates the `fetch` to cache the promise for the second <CodeStep step={3}>`getData`</CodeStep> to look-up.
If by the <CodeStep step={3}>second call</CodeStep> the promise is still _pending_, then `await` will pause for the result. The optimization is that while we wait on the `fetch`, React can continue with computational work, thus reducing the wait time for the <CodeStep step={3}>second call</CodeStep>.
If by the <CodeStep step={3}>second call</CodeStep> the promise is still _pending_, then `await` will pause for the result. The optimization is that while we wait on the `fetch`, React can continue with computational work, thus reducing the wait time for the <CodeStep step={3}>second call</CodeStep>.
If the promise is already settled, either to an error or the _fulfilled_ result, `await` will return that value immediately. In both outcomes, there is a performance benefit.
</DeepDive>
@@ -309,7 +309,7 @@ async function DemoProfile() {
React only provides cache access to the memoized function in a component. When calling <CodeStep step={1}>`getUser`</CodeStep> outside of a component, it will still evaluate the function but not read or update the cache.
This is because cache access is provided through a [context](/learn/passing-data-deeply-with-context) which is only accessibile from a component.
This is because cache access is provided through a [context](/learn/passing-data-deeply-with-context) which is only accessibile from a component.
</Pitfall>
@@ -343,7 +343,7 @@ function App() {
```
In this example, `App` renders two `WeatherReport`s with the same record. Even though both components do the same work, they cannot share work. `useMemo`'s cache is only local to the component.
However, `useMemo` does ensure that if `App` re-renders and the `record` object doesn't change, each component instance would skip work and use the memoized value of `avgTemp`. `useMemo` will only cache the last computation of `avgTemp` with the given dependencies.
However, `useMemo` does ensure that if `App` re-renders and the `record` object doesn't change, each component instance would skip work and use the memoized value of `avgTemp`. `useMemo` will only cache the last computation of `avgTemp` with the given dependencies.
#### `cache` {/*deep-dive-cache*/}
@@ -379,7 +379,7 @@ You should use [`memo`](reference/react/memo) to prevent a component re-renderin
'use client';
function WeatherReport({record}) {
const avgTemp = calculateAvg(record);
const avgTemp = calculateAvg(record);
// ...
}
@@ -396,7 +396,7 @@ function App() {
}
```
In this example, both `MemoWeatherReport` components will call `calculateAvg` when first rendered. However, if `App` re-renders, with no changes to `record`, none of the props have changed and `MemoWeatherReport` will not re-render.
In this example, both `MemoWeatherReport` components will call `calculateAvg` when first rendered. However, if `App` re-renders, with no changes to `record`, none of the props have changed and `MemoWeatherReport` will not re-render.
Compared to `useMemo`, `memo` memoizes the component render based on props vs. specific computations. Similar to `useMemo`, the memoized component only caches the last render with the last prop values. Once the props change, the cache invalidates and the component re-renders.

View File

@@ -103,7 +103,7 @@ export default function List({ children }) {
<div className="List">
{Children.map(children, (child, index) =>
cloneElement(child, {
isHighlighted: index === selectedIndex
isHighlighted: index === selectedIndex
})
)}
```
@@ -124,15 +124,15 @@ By cloning its children, the `List` can pass extra information to every `Row` in
<List>
<Row
title="Cabbage"
isHighlighted={true}
isHighlighted={true}
/>
<Row
title="Garlic"
isHighlighted={false}
isHighlighted={false}
/>
<Row
title="Apple"
isHighlighted={false}
isHighlighted={false}
/>
</List>
```
@@ -152,7 +152,7 @@ export default function App() {
{products.map(product =>
<Row
key={product.id}
title={product.title}
title={product.title}
/>
)}
</List>
@@ -169,7 +169,7 @@ export default function List({ children }) {
<div className="List">
{Children.map(children, (child, index) =>
cloneElement(child, {
isHighlighted: index === selectedIndex
isHighlighted: index === selectedIndex
})
)}
<hr />
@@ -246,7 +246,7 @@ Cloning children makes it hard to tell how the data flows through your app. Try
### Passing data with a render prop {/*passing-data-with-a-render-prop*/}
Instead of using `cloneElement`, consider accepting a *render prop* like `renderItem`. Here, `List` receives `renderItem` as a prop. `List` calls `renderItem` for every item and passes `isHighlighted` as an argument:
Instead of using `cloneElement`, consider accepting a *render prop* like `renderItem`. Here, `List` receives `renderItem` as a prop. `List` calls `renderItem` for every item and passes `isHighlighted` as an argument:
```js {1,7}
export default function List({ items, renderItem }) {
@@ -280,15 +280,15 @@ The end result is the same as with `cloneElement`:
<List>
<Row
title="Cabbage"
isHighlighted={true}
isHighlighted={true}
/>
<Row
title="Garlic"
isHighlighted={false}
isHighlighted={false}
/>
<Row
title="Apple"
isHighlighted={false}
isHighlighted={false}
/>
</List>
```

View File

@@ -75,7 +75,7 @@ experimental_taintUniqueValue(
### Prevent a token from being passed to Client Components {/*prevent-a-token-from-being-passed-to-client-components*/}
To ensure that sensitive information such as passwords, session tokens, or other unique values do not inadvertently get passed to Client Components, the `taintUniqueValue` function provides a layer of protection. When a value is tainted, any attempt to pass it to a Client Component will result in an error.
To ensure that sensitive information such as passwords, session tokens, or other unique values do not inadvertently get passed to Client Components, the `taintUniqueValue` function provides a layer of protection. When a value is tainted, any attempt to pass it to a Client Component will result in an error.
The `lifetime` argument defines the duration for which the value remains tainted. For values that should remain tainted indefinitely, objects like [`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis) or `process` can serve as the `lifetime` argument. These objects have a lifespan that spans the entire duration of your app's execution.
@@ -176,7 +176,7 @@ export function fetchAPI(url) {
}
```
Sometimes mistakes happen during refactoring and not all of your colleagues might know about this.
Sometimes mistakes happen during refactoring and not all of your colleagues might know about this.
To protect against this mistakes happening down the line we can "taint" the actual password:
```js

View File

@@ -328,7 +328,7 @@ const FormField = forwardRef(function FormField({ label, isRequired }, ref) {
ref={ref}
label={label}
value={value}
onChange={e => setValue(e.target.value)}
onChange={e => setValue(e.target.value)}
/>
{(isRequired && value === '') &&
<i>Required</i>

View File

@@ -112,7 +112,7 @@ label {
#### Should you add memo everywhere? {/*should-you-add-memo-everywhere*/}
If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful.
If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful.
Optimizing with `memo` is only valuable when your component re-renders often with the same exact props, and its re-rendering logic is expensive. If there is no perceptible lag when your component re-renders, `memo` is unnecessary. Keep in mind that `memo` is completely useless if the props passed to your component are *always different,* such as if you pass an object or a plain function defined during rendering. This is why you will often need [`useMemo`](/reference/react/useMemo#skipping-re-rendering-of-components) and [`useCallback`](/reference/react/useCallback#skipping-re-rendering-of-components) together with `memo`.
@@ -222,7 +222,7 @@ export default function MyApp() {
const [theme, setTheme] = useState('dark');
function handleClick() {
setTheme(theme === 'dark' ? 'light' : 'dark');
setTheme(theme === 'dark' ? 'light' : 'dark');
}
return (

View File

@@ -51,7 +51,7 @@ When a file marked `'use client'` is imported from a server component, [compatib
## Usage {/*usage*/}
<Wip>
This section is a work in progress.
This section is a work in progress.
This API can be used in any framework that supports React Server Components. You may find additional documentation from them.
* [Next.js documentation](https://nextjs.org/docs/getting-started/react-essentials)

View File

@@ -49,7 +49,7 @@ Alternatively, add `'use server';` at the very top of a file to mark all exports
## Usage {/*usage*/}
<Wip>
This section is a work in progress.
This section is a work in progress.
This API can be used in any framework that supports React Server Components. You may find additional documentation from them.
* [Next.js documentation](https://nextjs.org/docs/getting-started/react-essentials)

View File

@@ -71,7 +71,7 @@ import { use } from 'react';
function Button() {
const theme = use(ThemeContext);
// ...
// ...
```
`use` returns the <CodeStep step={2}>context value</CodeStep> for the <CodeStep step={1}>context</CodeStep> you passed. To determine the context value, React searches the component tree and finds **the closest context provider above** for that particular context.
@@ -490,7 +490,7 @@ Instead, call `use` outside any component closures, where the function that call
```jsx
function MessageComponent({messagePromise}) {
// ✅ `use` is being called from a component.
// ✅ `use` is being called from a component.
const message = use(messagePromise);
// ...
```

View File

@@ -124,7 +124,7 @@ function ProductPage({ productId, referrer, theme }) {
orderDetails,
});
}
return (
<div className={theme}>
{/* ... so ShippingForm's props will never be the same, and it will re-render every time */}
@@ -216,7 +216,7 @@ function useCallback(fn, dependencies) {
#### Should you add useCallback everywhere? {/*should-you-add-usecallback-everywhere*/}
If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful.
If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful.
Caching a function with `useCallback` is only valuable in a few cases:

View File

@@ -60,7 +60,7 @@ import { useContext } from 'react';
function Button() {
const theme = useContext(ThemeContext);
// ...
// ...
```
`useContext` returns the <CodeStep step={2}>context value</CodeStep> for the <CodeStep step={1}>context</CodeStep> you passed. To determine the context value, React searches the component tree and finds **the closest context provider above** for that particular context.
@@ -845,7 +845,7 @@ export default function AddTask() {
type: 'added',
id: nextId++,
text: text,
});
});
}}>Add</button>
</>
);
@@ -1292,7 +1292,7 @@ export const LevelContext = createContext(0);
You can pass any values via context, including objects and functions.
```js [[2, 10, "{ currentUser, login }"]]
```js [[2, 10, "{ currentUser, login }"]]
function MyApp() {
const [currentUser, setCurrentUser] = useState(null);

View File

@@ -40,7 +40,7 @@ function SearchPage() {
#### Returns {/*returns*/}
During the initial render, the returned deferred value will be the same as the value you provided. During updates, React will first attempt a re-render with the old value (so it will return the old value), and then try another re-render in background with the new value (so it will return the updated value).
During the initial render, the returned deferred value will be the same as the value you provided. During updates, React will first attempt a re-render with the old value (so it will return the old value), and then try another re-render in background with the new value (so it will return the updated value).
#### Caveats {/*caveats*/}
@@ -179,7 +179,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -285,7 +285,7 @@ input { margin: 10px; }
</Sandpack>
A common alternative UI pattern is to *defer* updating the list of results and to keep showing the previous results until the new results are ready. Call `useDeferredValue` to pass a deferred version of the query down:
A common alternative UI pattern is to *defer* updating the list of results and to keep showing the previous results until the new results are ready. Call `useDeferredValue` to pass a deferred version of the query down:
```js {3,11}
export default function App() {
@@ -394,7 +394,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -623,7 +623,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}

View File

@@ -45,7 +45,7 @@ function ChatRoom({ roomId }) {
#### Parameters {/*parameters*/}
* `setup`: The function with your Effect's logic. Your setup function may also optionally return a *cleanup* function. When your component is added to the DOM, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. After your component is removed from the DOM, React will run your cleanup function.
* **optional** `dependencies`: The list of all reactive values referenced inside of the `setup` code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is [configured for React](/learn/editor-setup#linting), it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like `[dep1, dep2, dep3]`. React will compare each dependency with its previous value using the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison. If you omit this argument, your Effect will re-run after every re-render of the component. [See the difference between passing an array of dependencies, an empty array, and no dependencies at all.](#examples-dependencies)
#### Returns {/*returns*/}
@@ -110,7 +110,7 @@ You need to pass two arguments to `useEffect`:
- Then, your <CodeStep step={1}>setup code</CodeStep> runs with the new props and state.
3. Your <CodeStep step={2}>cleanup code</CodeStep> runs one final time after your component is removed from the page *(unmounts).*
**Let's illustrate this sequence for the example above.**
**Let's illustrate this sequence for the example above.**
When the `ChatRoom` component above gets added to the page, it will connect to the chat room with the initial `serverUrl` and `roomId`. If either `serverUrl` or `roomId` change as a result of a re-render (say, if the user picks a different chat room in a dropdown), your Effect will *disconnect from the previous room, and connect to the next one.* When the `ChatRoom` component is removed from the page, your Effect will disconnect one last time.
@@ -1079,7 +1079,7 @@ If either `serverUrl` or `roomId` change, your Effect will reconnect to the chat
```js {8}
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
@@ -1433,7 +1433,7 @@ function Counter() {
}
```
Since `count` is a reactive value, it must be specified in the list of dependencies. However, that causes the Effect to cleanup and setup again every time the `count` changes. This is not ideal.
Since `count` is a reactive value, it must be specified in the list of dependencies. However, that causes the Effect to cleanup and setup again every time the `count` changes. This is not ideal.
To fix this, [pass the `c => c + 1` state updater](/reference/react/useState#updating-state-based-on-the-previous-state) to `setCount`:

View File

@@ -189,7 +189,7 @@ Inside React, `useId` is generated from the "parent path" of the calling compone
### Generating IDs for several related elements {/*generating-ids-for-several-related-elements*/}
If you need to give IDs to multiple related elements, you can call `useId` to generate a shared prefix for them:
If you need to give IDs to multiple related elements, you can call `useId` to generate a shared prefix for them:
<Sandpack>

View File

@@ -45,7 +45,7 @@ function useCSS(rule) {
#### Parameters {/*parameters*/}
* `setup`: The function with your Effect's logic. Your setup function may also optionally return a *cleanup* function. When your component is added to the DOM, but before any layout effects fire, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. When your component is removed from the DOM, React will run your cleanup function.
* **optional** `dependencies`: The list of all reactive values referenced inside of the `setup` code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is [configured for React](/learn/editor-setup#linting), it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like `[dep1, dep2, dep3]`. React will compare each dependency with its previous value using the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison algorithm. If you don't specify the dependencies at all, your Effect will re-run after every re-render of the component.
#### Returns {/*returns*/}

View File

@@ -48,7 +48,7 @@ function Tooltip() {
#### Parameters {/*parameters*/}
* `setup`: The function with your Effect's logic. Your setup function may also optionally return a *cleanup* function. Before your component is added to the DOM, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. Before your component is removed from the DOM, React will run your cleanup function.
* **optional** `dependencies`: The list of all reactive values referenced inside of the `setup` code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is [configured for React](/learn/editor-setup#linting), it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like `[dep1, dep2, dep3]`. React will compare each dependency with its previous value using the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison. If you omit this argument, your Effect will re-run after every re-render of the component.
#### Returns {/*returns*/}

View File

@@ -143,7 +143,7 @@ Also note that measuring performance in development will not give you the most a
#### Should you add useMemo everywhere? {/*should-you-add-usememo-everywhere*/}
If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful.
If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful.
Optimizing with `useMemo` is only valuable in a few cases:

View File

@@ -38,7 +38,7 @@ function MyComponent() {
#### Parameters {/*parameters*/}
* `reducer`: The reducer function that specifies how the state gets updated. It must be pure, should take the state and action as arguments, and should return the next state. State and action can be of any types.
* `reducer`: The reducer function that specifies how the state gets updated. It must be pure, should take the state and action as arguments, and should return the next state. State and action can be of any types.
* `initialArg`: The value from which the initial state is calculated. It can be a value of any type. How the initial state is calculated from it depends on the next `init` argument.
* **optional** `init`: The initializer function that should return the initial state. If it's not specified, the initial state is set to `initialArg`. Otherwise, the initial state is set to the result of calling `init(initialArg)`.
@@ -198,7 +198,7 @@ Actions can have any shape. By convention, it's common to pass objects with a `t
```js {5,9-12}
function Form() {
const [state, dispatch] = useReducer(reducer, { name: 'Taylor', age: 42 });
function handleButtonClick() {
dispatch({ type: 'incremented_age' });
}
@@ -290,7 +290,7 @@ export default function Form() {
dispatch({
type: 'changed_name',
nextName: e.target.value
});
});
}
return (

View File

@@ -605,8 +605,8 @@ export default function Form() {
<br />
(located in {person.artwork.city})
</p>
<img
src={person.artwork.image}
<img
src={person.artwork.image}
alt={person.artwork.title}
/>
</>

View File

@@ -107,7 +107,7 @@ It returns the <CodeStep step={3}>snapshot</CodeStep> of the data in the store.
React will use these functions to keep your component subscribed to the store and re-render it on changes.
For example, in the sandbox below, `todosStore` is implemented as an external store that stores data outside of React. The `TodosApp` component connects to that external store with the `useSyncExternalStore` Hook.
For example, in the sandbox below, `todosStore` is implemented as an external store that stores data outside of React. The `TodosApp` component connects to that external store with the `useSyncExternalStore` Hook.
<Sandpack>
@@ -408,7 +408,7 @@ This `subscribe` function is defined *inside* a component so it is different on
```js {4-7}
function ChatIndicator() {
const isOnline = useSyncExternalStore(subscribe, getSnapshot);
// 🚩 Always a different function, so React will resubscribe on every re-render
function subscribe() {
// ...
@@ -417,7 +417,7 @@ function ChatIndicator() {
// ...
}
```
React will resubscribe to your store if you pass a different `subscribe` function between re-renders. If this causes performance issues and you'd like to avoid resubscribing, move the `subscribe` function outside:
```js {6-9}
@@ -437,7 +437,7 @@ Alternatively, wrap `subscribe` into [`useCallback`](/reference/react/useCallbac
```js {4-8}
function ChatIndicator({ userId }) {
const isOnline = useSyncExternalStore(subscribe, getSnapshot);
// ✅ Same function as long as userId doesn't change
const subscribe = useCallback(() => {
// ...

View File

@@ -151,7 +151,7 @@ export default function TabContainer() {
function selectTab(nextTab) {
startTransition(() => {
setTab(nextTab);
setTab(nextTab);
});
}
@@ -823,7 +823,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -1017,7 +1017,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -1288,7 +1288,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -1332,7 +1332,7 @@ function use(promise) {
reason => {
promise.status = 'rejected';
promise.reason = reason;
},
},
);
throw promise;
}
@@ -1379,9 +1379,9 @@ async function getBio() {
setTimeout(resolve, 500);
});
return `The Beatles were an English rock band,
formed in Liverpool in 1960, that comprised
John Lennon, Paul McCartney, George Harrison
return `The Beatles were an English rock band,
formed in Liverpool in 1960, that comprised
John Lennon, Paul McCartney, George Harrison
and Ringo Starr.`;
}