Browse Source

[Beta] Use h4 for Challenge titles (#4980)

main
dan 2 years ago
committed by GitHub
parent
commit
0122c9aa8c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      beta/src/components/MDX/Challenges/Challenges.tsx
  2. 14
      beta/src/pages/apis/react/useContext.md
  3. 10
      beta/src/pages/apis/react/useReducer.md
  4. 12
      beta/src/pages/apis/react/useRef.md
  5. 24
      beta/src/pages/apis/react/useState.md
  6. 8
      beta/src/pages/learn/choosing-the-state-structure.md
  7. 6
      beta/src/pages/learn/conditional-rendering.md
  8. 8
      beta/src/pages/learn/extracting-state-logic-into-a-reducer.md
  9. 2
      beta/src/pages/learn/importing-and-exporting-components.md
  10. 6
      beta/src/pages/learn/javascript-in-jsx-with-curly-braces.md
  11. 6
      beta/src/pages/learn/keeping-components-pure.md
  12. 10
      beta/src/pages/learn/lifecycle-of-reactive-effects.md
  13. 8
      beta/src/pages/learn/manipulating-the-dom-with-refs.md
  14. 2
      beta/src/pages/learn/passing-data-deeply-with-context.md
  15. 6
      beta/src/pages/learn/passing-props-to-a-component.md
  16. 10
      beta/src/pages/learn/preserving-and-resetting-state.md
  17. 4
      beta/src/pages/learn/queueing-a-series-of-state-updates.md
  18. 6
      beta/src/pages/learn/reacting-to-input-with-state.md
  19. 8
      beta/src/pages/learn/referencing-values-with-refs.md
  20. 8
      beta/src/pages/learn/removing-effect-dependencies.md
  21. 8
      beta/src/pages/learn/rendering-lists.md
  22. 4
      beta/src/pages/learn/responding-to-events.md
  23. 10
      beta/src/pages/learn/reusing-logic-with-custom-hooks.md
  24. 8
      beta/src/pages/learn/separating-events-from-effects.md
  25. 4
      beta/src/pages/learn/sharing-state-between-components.md
  26. 8
      beta/src/pages/learn/state-a-components-memory.md
  27. 2
      beta/src/pages/learn/state-as-a-snapshot.md
  28. 8
      beta/src/pages/learn/synchronizing-with-effects.md
  29. 8
      beta/src/pages/learn/updating-arrays-in-state.md
  30. 6
      beta/src/pages/learn/updating-objects-in-state.md
  31. 2
      beta/src/pages/learn/writing-markup-with-jsx.md
  32. 8
      beta/src/pages/learn/you-might-not-need-an-effect.md
  33. 8
      beta/src/pages/learn/your-first-component.md

2
beta/src/components/MDX/Challenges/Challenges.tsx

@ -51,7 +51,7 @@ const parseChallengeContents = (
challenge.hint = child;
break;
}
case 'h3': {
case 'h4': {
challenge.order = contents.length + 1;
challenge.name = props.children;
challenge.id = props.id;

14
beta/src/pages/apis/react/useContext.md

@ -177,7 +177,7 @@ Now any `Button` inside of the provider will receive the current `theme` value.
<Recipes titleText="Examples of updating context" titleId="examples-basic">
### Updating a value via context {/*updating-a-value-via-context*/}
#### Updating a value via context {/*updating-a-value-via-context*/}
In this example, the `MyApp` component holds a state variable which is then passed to the `ThemeContext` provider. Checking the "Dark mode" checkbox updates the state. Changing the provided value re-renders all the components using that context.
@ -281,7 +281,7 @@ Note that `value="dark"` passes the `"dark"` string, but `value={theme}` passes
<Solution />
### Updating an object via context {/*updating-an-object-via-context*/}
#### Updating an object via context {/*updating-an-object-via-context*/}
In this example, there is a `currentUser` state variable which holds an object. You combine `{ currentUser, setCurrentUser }` into a single object and pass it down through the context inside the `value={}`. This lets any component below, such as `LoginButton`, read both `currentUser` and `setCurrentUser`, and then call `setCurrentUser` when needed.
@ -373,7 +373,7 @@ label {
<Solution />
### Multiple contexts {/*multiple-contexts*/}
#### Multiple contexts {/*multiple-contexts*/}
In this example, there are two independent contexts. `ThemeContext` provides the current theme, which is a string, while `CurrentUserContext` holds the object representing the current user.
@ -540,7 +540,7 @@ label {
<Solution />
### Extracting providers to a component {/*extracting-providers-to-a-component*/}
#### Extracting providers to a component {/*extracting-providers-to-a-component*/}
As your app grows, it is expected that you'll have a "pyramid" of contexts closer to the root of your app. There is nothing wrong with that. However, if you dislike the nesting aesthetically, you can extract the providers into a single component. In this example, `MyProviders` hides the "plumbing" and renders the children passed to it inside the necessary providers. Note that the `theme` and `setTheme` state is needed in `MyApp` itself, so `MyApp` still owns that piece of the state.
@ -715,7 +715,7 @@ label {
<Solution />
### Scaling up with context and a reducer {/*scaling-up-with-context-and-a-reducer*/}
#### Scaling up with context and a reducer {/*scaling-up-with-context-and-a-reducer*/}
In larger apps, it is common to combine context with a [reducer](/apis/react/useReducer) to extract the logic related to some state out of components. In this example, all the "wiring" is hidden in the `TasksContext.js`, which contains a reducer and two separate contexts.
@ -1058,7 +1058,7 @@ You can nest and override providers as many times as you need.
<Recipes title="Examples of overriding context">
### Overriding a theme {/*overriding-a-theme*/}
#### Overriding a theme {/*overriding-a-theme*/}
Here, the button *inside* the `Footer` receives a different context value (`"light"`) than the buttons outside (`"dark"`).
@ -1164,7 +1164,7 @@ footer {
<Solution />
### Automatically nested headings {/*automatically-nested-headings*/}
#### Automatically nested headings {/*automatically-nested-headings*/}
You can "accumulate" information when you nest context providers. In this example, the `Section` component keeps track of the `LevelContext` which specifies the depth of the section nesting. It reads the `LevelContext` from the parent section, and provides the `LevelContext` number increased by one to its children. As a result, the `Heading` component can automatically decide which of the `<h1>`, `<h2>`, `<h3>`, ..., tags to use based on how many `Section` components it is nested inside of.

10
beta/src/pages/apis/react/useReducer.md

@ -191,7 +191,7 @@ Read [updating objects in state](/learn/updating-objects-in-state) and [updating
<Recipes titleText="Basic useReducer examples" titleId="examples-basic">
### Form (object) {/*form-object*/}
#### Form (object) {/*form-object*/}
In this example, the reducer manages a state object with two fields: `name` and `age`.
@ -257,7 +257,7 @@ button { display: block; margin-top: 10px; }
<Solution />
### Todo list (array) {/*todo-list-array*/}
#### Todo list (array) {/*todo-list-array*/}
In this example, the reducer manages an array of tasks. The array needs to be updated [without mutation](/learn/updating-arrays-in-state).
@ -450,7 +450,7 @@ ul, li { margin: 0; padding: 0; }
<Solution />
### Writing concise update logic with Immer {/*writing-concise-update-logic-with-immer*/}
#### Writing concise update logic with Immer {/*writing-concise-update-logic-with-immer*/}
If updating arrays and objects without mutation feels tedious, you can use a library like [Immer](https://github.com/immerjs/use-immer#useimmerreducer) to reduce repetitive code. Immer lets you write concise code as if you were mutating objects, but under the hood it performs immutable updates:
@ -698,7 +698,7 @@ In the above example, `createInitialState` takes a `username` argument. If your
<Recipes titleText="The difference between passing an initializer and passing the initial state directly" titleId="examples-initializer">
### Passing the initializer function {/*passing-the-initializer-function*/}
#### Passing the initializer function {/*passing-the-initializer-function*/}
This example passes the initializer function, so the `createInitialState` function only runs during initialization. It does not run when component re-renders, such as when you type into the input.
@ -786,7 +786,7 @@ export default function TodoList({ username }) {
<Solution />
### Passing the initial state directly {/*passing-the-initial-state-directly*/}
#### Passing the initial state directly {/*passing-the-initial-state-directly*/}
This example **does not** pass the initializer function, so the `createInitialState` function runs on every render, such as when you type into the input. There is no observable difference in behavior, but this code is less efficient.

12
beta/src/pages/apis/react/useRef.md

@ -71,7 +71,7 @@ Changing a ref does not trigger a re-render, so refs are not appropriate for sto
<Recipes titleText="Examples of referencing a value with useRef" titleId="examples-value">
### Click counter {/*click-counter*/}
#### Click counter {/*click-counter*/}
This component uses a ref to keep track of how many times the button was clicked. Note that it's okay to use a ref instead of state here because the click count is only read and written in an event handler.
@ -102,7 +102,7 @@ If you show `{ref.current}` in the JSX, the number won't update on click. This i
<Solution />
### A stopwatch {/*a-stopwatch*/}
#### A stopwatch {/*a-stopwatch*/}
This example uses a combination of state and refs. Both `startTime` and `now` are state variables because they are used for rendering. But we also need to hold an [interval ID](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) so that we can stop the interval on button press. Since the interval ID is not used for rendering, it's appropriate to keep it in a ref, and manually update it.
@ -238,7 +238,7 @@ Read more about [manipulating the DOM with refs](/learn/manipulating-the-dom-wit
<Recipes titleText="Examples of manipulating the DOM with useRef" titleId="examples-dom">
### Focusing a text input {/*focusing-a-text-input*/}
#### Focusing a text input {/*focusing-a-text-input*/}
In this example, clicking the button will focus the input:
@ -269,7 +269,7 @@ export default function Form() {
<Solution />
### Scrolling an image into view {/*scrolling-an-image-into-view*/}
#### Scrolling an image into view {/*scrolling-an-image-into-view*/}
In this example, clicking the button will scroll an image into view. It uses a ref to the list DOM node, and then calls DOM [`querySelectorAll`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll) API to find the image we want to scroll to.
@ -362,7 +362,7 @@ li {
<Solution />
### Playing and pausing a video {/*playing-and-pausing-a-video*/}
#### Playing and pausing a video {/*playing-and-pausing-a-video*/}
This example uses a ref to call [`play()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play) and [`pause()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/pause) on a `<video>` DOM node.
@ -415,7 +415,7 @@ button { display: block; margin-bottom: 20px; }
<Solution />
### Exposing a ref to your own component {/*exposing-a-ref-to-your-own-component*/}
#### Exposing a ref to your own component {/*exposing-a-ref-to-your-own-component*/}
Sometimes, you may want to let the parent component manipulate the DOM inside of your component. For example, maybe you're writing a `MyInput` component, but you want the parent to be able to focus the input (which the parent has no access to). You can use a combination of `useRef` to hold the input and [`forwardRef`](/apis/react/forwardRef) to expose it to the parent component. Read a [detailed walkthrough](/learn/manipulating-the-dom-with-refs#accessing-another-components-dom-nodes) here.

24
beta/src/pages/apis/react/useState.md

@ -80,7 +80,7 @@ It only affects what `useState` will return starting from the *next* render.
<Recipes titleText="Basic useState examples" titleId="examples-basic">
### Counter (number) {/*counter-number*/}
#### Counter (number) {/*counter-number*/}
In this example, the `count` state variable holds a number. Clicking the button increments it.
@ -108,7 +108,7 @@ export default function Counter() {
<Solution />
### Text field (string) {/*text-field-string*/}
#### Text field (string) {/*text-field-string*/}
In this example, the `text` state variable holds a string. When you type, `handleChange` reads the latest input value from the browser input DOM element, and calls `setText` to update the state. This allows you to display the current `text` below.
@ -140,7 +140,7 @@ export default function MyInput() {
<Solution />
### Checkbox (boolean) {/*checkbox-boolean*/}
#### Checkbox (boolean) {/*checkbox-boolean*/}
In this example, the `liked` state variable holds a boolean. When you click the input, `setLiked` updates the `liked` state variable with whether the browser checkbox input is checked. The `liked` variable is used to render the text below the checkbox.
@ -176,7 +176,7 @@ export default function MyCheckbox() {
<Solution />
### Form (two variables) {/*form-two-variables*/}
#### Form (two variables) {/*form-two-variables*/}
You can declare more than one state variable in the same component. Each state variable is completely independent.
@ -268,7 +268,7 @@ If you prefer consistency over slightly more verbose syntax, it's reasonable to
<Recipes titleText="The difference between passing an updater and passing the next state directly" titleId="examples-updater">
### Passing the updater function {/*passing-the-updater-function*/}
#### Passing the updater function {/*passing-the-updater-function*/}
This example passes the updater function, so the "+3" button works.
@ -309,7 +309,7 @@ h1 { display: block; margin: 10px; }
<Solution />
### Passing the next state directly {/*passing-the-next-state-directly*/}
#### Passing the next state directly {/*passing-the-next-state-directly*/}
This example **does not** pass the updater function, so the "+3" button **doesn't work as intended**.
@ -377,7 +377,7 @@ Read [updating objects in state](/learn/updating-objects-in-state) and [updating
<Recipes titleText="Examples of objects and arrays in state" titleId="examples-objects">
### Form (object) {/*form-object*/}
#### Form (object) {/*form-object*/}
In this example, the `form` state variable holds an object. Each input has a change handler that calls `setForm` with the next state of the entire form. The `{ ...form }` spread syntax ensures that the state object is replaced rather than mutated.
@ -450,7 +450,7 @@ input { margin-left: 5px; }
<Solution />
### Form (nested object) {/*form-nested-object*/}
#### Form (nested object) {/*form-nested-object*/}
In this example, the state is more nested. When you update nested state, you need to create a copy of the object you're updating, as well as any objects "containing" it on the way upwards. Read [updating a nested object](/learn/updating-objects-in-state#updating-a-nested-object) to learn more.
@ -562,7 +562,7 @@ img { width: 200px; height: 200px; }
<Solution />
### List (array) {/*list-array*/}
#### List (array) {/*list-array*/}
In this example, the `todos` state variable holds an array. Each button handler calls `setTodos` with the next version of that array. The `[...todos]` spread syntax, `todos.map()` and `todos.filter()` ensure the state array is replaced rather than mutated.
@ -729,7 +729,7 @@ ul, li { margin: 0; padding: 0; }
<Solution />
### Writing concise update logic with Immer {/*writing-concise-update-logic-with-immer*/}
#### Writing concise update logic with Immer {/*writing-concise-update-logic-with-immer*/}
If updating arrays and objects without mutation feels tedious, you can use a library like [Immer](https://github.com/immerjs/use-immer) to reduce repetitive code. Immer lets you write concise code as if you were mutating objects, but under the hood it performs immutable updates:
@ -846,7 +846,7 @@ React may [call your initializers twice](#my-initializer-or-updater-function-run
<Recipes titleText="The difference between passing an initializer and passing the initial state directly" titleId="examples-initializer">
### Passing the initializer function {/*passing-the-initializer-function*/}
#### Passing the initializer function {/*passing-the-initializer-function*/}
This example passes the initializer function, so the `createInitialTodos` function only runs during initialization. It does not run when component re-renders, such as when you type into the input.
@ -899,7 +899,7 @@ export default function TodoList() {
<Solution />
### Passing the initial state directly {/*passing-the-initial-state-directly*/}
#### Passing the initial state directly {/*passing-the-initial-state-directly*/}
This example **does not** pass the initializer function, so the `createInitialTodos` function runs on every render, such as when you type into the input. There is no observable difference in behavior, but this code is less efficient.

8
beta/src/pages/learn/choosing-the-state-structure.md

@ -1854,7 +1854,7 @@ Sometimes, you can also reduce state nesting by moving some of the nested state
<Challenges>
### Fix a component that's not updating {/*fix-a-component-thats-not-updating*/}
#### Fix a component that's not updating {/*fix-a-component-thats-not-updating*/}
This `Clock` component receives two props: `color` and `time`. When you select a different color in the select box, the `Clock` component receives a different `color` prop from its parent component. However, for some reason, the displayed color doesn't update. Why? Fix the problem.
@ -2017,7 +2017,7 @@ export default function App() {
</Solution>
### Fix a broken packing list {/*fix-a-broken-packing-list*/}
#### Fix a broken packing list {/*fix-a-broken-packing-list*/}
This packing list has a footer that shows how many items are packed, and how many items there are overall. It seems to work at first, but it is buggy. For example, if you mark an item as packed and then delete it, the counter will not be updated correctly. Fix the counter so that it's always correct.
@ -2301,7 +2301,7 @@ Notice how the event handlers are only concerned with calling `setItems` after t
</Solution>
### Fix the disappearing selection {/*fix-the-disappearing-selection*/}
#### Fix the disappearing selection {/*fix-the-disappearing-selection*/}
There is a list of `letters` in state. When you hover or focus a particular letter, it gets highlighted. The currently highlighted letter is stored in the `highlightedLetter` state variable. You can "star" and "unstar" individual letters, which updates the `letters` array in state.
@ -2521,7 +2521,7 @@ li { border-radius: 5px; }
</Solution>
### Implement multiple selection {/*implement-multiple-selection*/}
#### Implement multiple selection {/*implement-multiple-selection*/}
In this example, each `Letter` has an `isSelected` prop and an `onToggle` handler that marks it as selected. This works, but the state is stored as a `selectedId` (either `null` or an ID), so only one letter can get selected at any given time.

6
beta/src/pages/learn/conditional-rendering.md

@ -452,7 +452,7 @@ If you're not familiar with JavaScript, this variety of styles might seem overwh
<Challenges>
### Show an icon for incomplete items with `? :` {/*show-an-icon-for-incomplete-items-with--*/}
#### Show an icon for incomplete items with `? :` {/*show-an-icon-for-incomplete-items-with--*/}
Use the conditional operator (`cond ? a : b`) to render a ❌ if `isPacked` isn’t `true`.
@ -532,7 +532,7 @@ export default function PackingList() {
</Solution>
### Show the item importance with `&&` {/*show-the-item-importance-with-*/}
#### Show the item importance with `&&` {/*show-the-item-importance-with-*/}
In this example, each `Item` receives a numerical `importance` prop. Use the `&&` operator to render "_(Importance: X)_" in italics, but only for items that have non-zero importance. Your item list should end up looking like this:
@ -628,7 +628,7 @@ In this solution, two separate conditions are used to insert a space between the
</Solution>
### Refactor a series of `? :` to `if` and variables {/*refactor-a-series-of---to-if-and-variables*/}
#### Refactor a series of `? :` to `if` and variables {/*refactor-a-series-of---to-if-and-variables*/}
This `Drink` component uses a series of `? :` conditions to show different information depending on whether the `name` prop is `"tea"` or `"coffee"`. The problem is that the information about each drink is spread across multiple conditions. Refactor this code to use a single `if` statement instead of three `? :` conditions.

8
beta/src/pages/learn/extracting-state-logic-into-a-reducer.md

@ -1115,7 +1115,7 @@ Reducers must be pure, so they shouldn't mutate state. But Immer provides you wi
<Challenges>
### Dispatch actions from event handlers {/*dispatch-actions-from-event-handlers*/}
#### Dispatch actions from event handlers {/*dispatch-actions-from-event-handlers*/}
Currently, the event handlers in `ContactList.js` and `Chat.js` have `// TODO` comments. This is why typing into the input doesn't work, and clicking on the buttons doesn't change the selected recipient.
@ -1467,7 +1467,7 @@ textarea {
</Solution>
### Clear the input on sending a message {/*clear-the-input-on-sending-a-message*/}
#### Clear the input on sending a message {/*clear-the-input-on-sending-a-message*/}
Currently, pressing "Send" doesn't do anything. Add an event handler to the "Send" button that will:
@ -1970,7 +1970,7 @@ With either solution, it's important that you **don't** place the `alert` inside
</Solution>
### Restore input values when switching between tabs {/*restore-input-values-when-switching-between-tabs*/}
#### Restore input values when switching between tabs {/*restore-input-values-when-switching-between-tabs*/}
In this example, switching between different recipients always clears the text input:
@ -2385,7 +2385,7 @@ Notably, you didn't need to change any of the event handlers to implement this d
</Solution>
### Implement `useReducer` from scratch {/*implement-usereducer-from-scratch*/}
#### Implement `useReducer` from scratch {/*implement-usereducer-from-scratch*/}
In the earlier examples, you imported the `useReducer` Hook from React. This time, you will implement *the `useReducer` Hook itself!* Here is a stub to get your started. It shouldn't take more than 10 lines of code.

2
beta/src/pages/learn/importing-and-exporting-components.md

@ -241,7 +241,7 @@ On this page you learned:
<Challenges>
### Split the components further {/*split-the-components-further*/}
#### Split the components further {/*split-the-components-further*/}
Currently, `Gallery.js` exports both `Profile` and `Gallery`, which is a bit confusing.

6
beta/src/pages/learn/javascript-in-jsx-with-curly-braces.md

@ -245,7 +245,7 @@ Now you know almost everything about JSX:
<Challenges>
### Fix the mistake {/*fix-the-mistake*/}
#### Fix the mistake {/*fix-the-mistake*/}
This code crashes with an error saying `Objects are not valid as a React child`:
@ -337,7 +337,7 @@ body > div > div { padding: 20px; }
</Solution>
### Extract information into an object {/*extract-information-into-an-object*/}
#### Extract information into an object {/*extract-information-into-an-object*/}
Extract the image URL into the `person` object.
@ -424,7 +424,7 @@ body > div > div { padding: 20px; }
</Solution>
### Write an expression inside JSX curly braces {/*write-an-expression-inside-jsx-curly-braces*/}
#### Write an expression inside JSX curly braces {/*write-an-expression-inside-jsx-curly-braces*/}
In the object below, the full image URL is split into four parts: base URL, `imageId`, `imageSize`, and file extension.

6
beta/src/pages/learn/keeping-components-pure.md

@ -225,7 +225,7 @@ Every new React feature we're building takes advantage of purity. From data fetc
<Challenges>
### Fix a broken clock {/*fix-a-broken-clock*/}
#### Fix a broken clock {/*fix-a-broken-clock*/}
This component tries to set the `<h1>`'s CSS class to `"night"` during the time from midnight to six hours in the morning, and `"day"` at all other times. However, it doesn't work. Can you fix this component?
@ -362,7 +362,7 @@ In this example, the side effect (modifying the DOM) was not necessary at all. Y
</Solution>
### Fix a broken profile {/*fix-a-broken-profile*/}
#### Fix a broken profile {/*fix-a-broken-profile*/}
Two `Profile` components are rendered side by side with different data. Press "Collapse" on the first profile, and then "Expand" it. You'll notice that both profiles now show the same person. This is a bug.
@ -571,7 +571,7 @@ Remember that React does not guarantee that component functions will execute in
</Solution>
### Fix a broken story tray {/*fix-a-broken-story-tray*/}
#### Fix a broken story tray {/*fix-a-broken-story-tray*/}
The CEO of your company is asking you to add "stories" to your online clock app, and you can't say no. You've written a `StoryTray` component that accepts a list of `stories`, followed by a "Create Story" placeholder.

10
beta/src/pages/learn/lifecycle-of-reactive-effects.md

@ -769,7 +769,7 @@ On the [next](/learn/separating-events-from-effects) [pages](/learn/removing-eff
<Challenges>
### Fix reconnecting on every keystroke {/*fix-reconnecting-on-every-keystroke*/}
#### Fix reconnecting on every keystroke {/*fix-reconnecting-on-every-keystroke*/}
In this example, the `ChatRoom` component connects to the chat room when the component mounts, disconnects when it unmounts, and reconnects when you select a different chat room. This behavior is correct, so you need to keep it working.
@ -929,7 +929,7 @@ button { margin-left: 10px; }
</Solution>
### Switch synchronization on and off {/*switch-synchronization-on-and-off*/}
#### Switch synchronization on and off {/*switch-synchronization-on-and-off*/}
In this example, an Effect subscribes to the window [`pointermove`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointermove_event) event to move a pink dot on the screen. Try hovering over the preview area (or touching the screen if you're on a mobile device), and see how the pink dot follows your movement.
@ -1111,7 +1111,7 @@ In both of these cases, `canMove` is a reactive variable that you read inside th
</Solution>
### Investigate a stale value bug {/*investigate-a-stale-value-bug*/}
#### Investigate a stale value bug {/*investigate-a-stale-value-bug*/}
In this example, the pink dot should move when the checkbox if on, and should stop moving when the checkbox is off. The logic for this has already been implemented: the `handleMove` event handler checks the `canMove` state variable.
@ -1309,7 +1309,7 @@ You'll learn a more general approach to this type of problem in [Separating Even
</Solution>
### Fix a connection switch {/*fix-a-connection-switch*/}
#### Fix a connection switch {/*fix-a-connection-switch*/}
In this example, the chat service in `chat.js` exposes two different APIs: `createEncryptedConnection` and `createUnencryptedConnection`. The root `App` component lets the user choose whether to use encryption or not, and then passes down the corresponding API method to the child `ChatRoom` component as the `createConnection` prop.
@ -1611,7 +1611,7 @@ In this version, the `App` component passes a boolean prop instead of a function
</Solution>
### Populate a chain of select boxes {/*populate-a-chain-of-select-boxes*/}
#### Populate a chain of select boxes {/*populate-a-chain-of-select-boxes*/}
In this example, there are two select boxes. One select box lets the user picks a planet. Another select box lets the user pick a place *on that planet.* The second box doesn't work yet. Your task is to make it show the places on the chosen planet.

8
beta/src/pages/learn/manipulating-the-dom-with-refs.md

@ -694,7 +694,7 @@ However, this doesn't mean that you can't do it at all. It requires caution. **Y
<Challenges>
### Play and pause the video {/*play-and-pause-the-video*/}
#### Play and pause the video {/*play-and-pause-the-video*/}
In this example, the button toggles a state variable to switch between a playing and a paused state. However, in order to actually play or pause the video, toggling state is not enough. You also need to call [`play()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play) and [`pause()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/pause) on the DOM element for the `<video>`. Add a ref to it, and make the button work.
@ -790,7 +790,7 @@ In order to handle the built-in browser controls, you can add `onPlay` and `onPa
</Solution>
### Focus the search field {/*focus-the-search-field*/}
#### Focus the search field {/*focus-the-search-field*/}
Make it so that clicking the "Search" button puts focus into the field.
@ -854,7 +854,7 @@ button { display: block; margin-bottom: 10px; }
</Solution>
### Scrolling an image carousel {/*scrolling-an-image-carousel*/}
#### Scrolling an image carousel {/*scrolling-an-image-carousel*/}
This image carousel has a "Next" button that switches the active image. Make the gallery scroll horizontally to the active image on click. You will want to call [`scrollIntoView()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView) on the DOM node of the active image:
@ -1080,7 +1080,7 @@ img {
</Solution>
### Focus the search field with separate components {/*focus-the-search-field-with-separate-components*/}
#### Focus the search field with separate components {/*focus-the-search-field-with-separate-components*/}
Make it so that clicking the "Search" button puts focus into the field. Note that each component is defined in a separate file and shouldn't be moved out of it. How do you connect them together?

2
beta/src/pages/learn/passing-data-deeply-with-context.md

@ -873,7 +873,7 @@ In general, if some information is needed by distant components in different par
<Challenges>
### Replace prop drilling with context {/*replace-prop-drilling-with-context*/}
#### Replace prop drilling with context {/*replace-prop-drilling-with-context*/}
In this example, toggling the checkbox changes the `imageSize` prop passed to each `<PlaceImage>`. The checkbox state is held in the top-level `App` component, but each `<PlaceImage>` needs to be aware of it.

6
beta/src/pages/learn/passing-props-to-a-component.md

@ -425,7 +425,7 @@ However, props are [immutable](https://en.wikipedia.org/wiki/Immutable_object)
<Challenges>
### Extract a component {/*extract-a-component*/}
#### Extract a component {/*extract-a-component*/}
This `Gallery` component contains some very similar markup for two profiles. Extract a `Profile` component out of it to reduce the duplication. You'll need to choose what props to pass to it.
@ -727,7 +727,7 @@ Although the syntax looks slightly different because you're describing propertie
</Solution>
### Adjust the image size based on a prop {/*adjust-the-image-size-based-on-a-prop*/}
#### Adjust the image size based on a prop {/*adjust-the-image-size-based-on-a-prop*/}
In this example, `Avatar` receives a numeric `size` prop which determines the `<img>` width and height. The `size` prop is set to `40` in this example. However, if you open the image in a new tab, you'll notice that the image itself is larger (`160` pixels). The real image size is determined by which thumbnail size you're requesting.
@ -919,7 +919,7 @@ Props let you encapsulate logic like this inside the `Avatar` component (and cha
</Solution>
### Passing JSX in a `children` prop {/*passing-jsx-in-a-children-prop*/}
#### Passing JSX in a `children` prop {/*passing-jsx-in-a-children-prop*/}
Extract a `Card` component from the markup below, and use the `children` prop to pass different JSX to it:

10
beta/src/pages/learn/preserving-and-resetting-state.md

@ -1258,7 +1258,7 @@ No matter which strategy you pick, a chat _with Alice_ is conceptually distinct
<Challenges>
### Fix disappearing input text {/*fix-disappearing-input-text*/}
#### Fix disappearing input text {/*fix-disappearing-input-text*/}
This example shows a message when you press the button. However, pressing the button also accidentally resets the input. Why does this happen? Fix it so that pressing the button does not reset the input text.
@ -1409,7 +1409,7 @@ This way, `Form` is always the second child, so it stays in the same position an
</Solution>
### Swap two form fields {/*swap-two-form-fields*/}
#### Swap two form fields {/*swap-two-form-fields*/}
This form lets you enter first and last name. It also has a checkbox controlling which field goes first. When you tick the checkbox, the "Last name" field will appear before the "First name" field.
@ -1543,7 +1543,7 @@ label { display: block; margin: 10px 0; }
</Solution>
### Reset a detail form {/*reset-a-detail-form*/}
#### Reset a detail form {/*reset-a-detail-form*/}
This is an editable contact list. You can edit the selected contact's details and then either press "Save" to update it, or "Reset" to undo your changes.
@ -1852,7 +1852,7 @@ button {
</Solution>
### Clear an image while it's loading {/*clear-an-image-while-its-loading*/}
#### Clear an image while it's loading {/*clear-an-image-while-its-loading*/}
When you press "Next", the browser starts loading the next image. However, because it's displayed in the same `<img>` tag, by default you would still see the previous image until the next one loads. This may be undesirable if it's important for the text to always match the image. Change it so that the moment you press "Next," the previous image immediately clears.
@ -1996,7 +1996,7 @@ img { width: 150px; height: 150px; }
</Solution>
### Fix misplaced state in the list {/*fix-misplaced-state-in-the-list*/}
#### Fix misplaced state in the list {/*fix-misplaced-state-in-the-list*/}
In this list, each `Contact` has state that determines whether "Show email" has been pressed for it. Press "Show email" for Alice, and then tick the "Show in reverse order" checkbox. You will notice that it's _Taylor's_ email that is expanded now, but Alice's--which has moved to the bottom--appears collapsed.

4
beta/src/pages/learn/queueing-a-series-of-state-updates.md

@ -268,7 +268,7 @@ If you prefer more verbose code, another common convention is to repeat the full
<Challenges>
### Fix a request counter {/*fix-a-request-counter*/}
#### Fix a request counter {/*fix-a-request-counter*/}
You're working on an art marketplace app that lets the user submit multiple orders for an art item at the same time. Each time the user presses the "Buy" button, the "Pending" counter should increase by one. After three seconds, the "Pending" counter should decrease, and the "Completed" counter should increase.
@ -364,7 +364,7 @@ This ensures that when you increment or decrement a counter, you do it in relati
</Solution>
### Implement the state queue yourself {/*implement-the-state-queue-yourself*/}
#### Implement the state queue yourself {/*implement-the-state-queue-yourself*/}
In this challenge, you will reimplement a tiny part of React from scratch! It's not as hard as it sounds.

6
beta/src/pages/learn/reacting-to-input-with-state.md

@ -495,7 +495,7 @@ Although this code is longer than the original imperative example, it is much le
<Challenges>
### Add and remove a CSS class {/*add-and-remove-a-css-class*/}
#### Add and remove a CSS class {/*add-and-remove-a-css-class*/}
Make it so that clicking on the picture *removes* the `background--active` CSS class from the outer `<div>`, but *adds* the `picture--active` class to the `<img>`. Clicking the background again should restore the original CSS classes.
@ -693,7 +693,7 @@ Keep in mind that if two different JSX chunks describe the same tree, their nest
</Solution>
### Profile editor {/*profile-editor*/}
#### Profile editor {/*profile-editor*/}
Here is a small form implemented with plain JavaScript and DOM. Play with it to understand its behavior:
@ -895,7 +895,7 @@ Compare this solution to the original imperative code. How are they different?
</Solution>
### Refactor the imperative solution without React {/*refactor-the-imperative-solution-without-react*/}
#### Refactor the imperative solution without React {/*refactor-the-imperative-solution-without-react*/}
Here is the original sandbox from the previous challenge, written imperatively without React:

8
beta/src/pages/learn/referencing-values-with-refs.md

@ -300,7 +300,7 @@ You can point a ref to any value. However, the most common use case for a ref is
<Challenges>
### Fix a broken chat input {/*fix-a-broken-chat-input*/}
#### Fix a broken chat input {/*fix-a-broken-chat-input*/}
Type a message and click "Send". You will notice there is a three second delay before you see the "Sent!" alert. During this delay, you can see an "Undo" button. Click it. This "Undo" button is supposed to stop the "Sent!" message from appearing. It does this by calling [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) for the timeout ID saved during `handleSend`. However, even after "Undo" is clicked, the "Sent!" message still appears. Find why it doesn't work, and fix it.
@ -411,7 +411,7 @@ export default function Chat() {
</Solution>
### Fix a component failing to re-render {/*fix-a-component-failing-to-re-render*/}
#### Fix a component failing to re-render {/*fix-a-component-failing-to-re-render*/}
This button is supposed to toggle between showing "On" and "Off". However, it always shows "Off". What is wrong with this code? Fix it.
@ -461,7 +461,7 @@ export default function Toggle() {
</Solution>
### Fix debouncing {/*fix-debouncing*/}
#### Fix debouncing {/*fix-debouncing*/}
In this example, all button click handlers are ["debounced"](https://redd.one/blog/debounce-vs-throttle). To see what this means, press one of the buttons. Notice how the message appears a second later. If you press the button while waiting for the message, the timer will reset. So if you keep clicking the same button fast many times, the message won't appear until a second *after* you stop clicking. Debouncing lets you delay some action until the user "stops doing things".
@ -578,7 +578,7 @@ button { display: block; margin: 10px; }
</Solution>
### Read the latest state {/*read-the-latest-state*/}
#### Read the latest state {/*read-the-latest-state*/}
In this example, after you press "Send", there is a small delay before the message is shown. Type "hello", press Send, and then quickly edit the input again. Despite your edits, the alert would still show "hello" (which was the value of state [at the time](/learn/state-as-a-snapshot#state-over-time) the button was clicked).

8
beta/src/pages/learn/removing-effect-dependencies.md

@ -1167,7 +1167,7 @@ This only works for [pure](/learn/keeping-components-pure) functions because the
<Challenges>
### Fix a resetting interval
#### Fix a resetting interval
This Effect sets up an interval that ticks every second. You've noticed something strange happening: it seems like the interval gets destroyed and re-created every time it ticks. Fix the code so that the interval doesn't get constantly re-created.
@ -1239,7 +1239,7 @@ Instead of reading `count` inside the Effect, you pass a `c => c + 1` instructio
</Solution>
### Fix a retriggering animation
#### Fix a retriggering animation
In this example, when you press "Show", a welcome message fades in. The animation takes a second. When you press "Remove", the welcome message immediately disappears. The logic for the fade-in animation is implemented in the `animation.js` file as plain JavaScript [animation loop](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame). You don't need to change that logic. You can treat it as a third-party library. Your Effect creates an instance of `FadeInAnimation` for the DOM node, and then calls `start(duration)` or `stop()` to control the animation. The `duration` is controlled by a slider. Adjust the slider and see how the animation changes.
@ -1509,7 +1509,7 @@ Event functions like `onAppear` are not reactive, so you can read `duration` ins
</Solution>
### Fix a reconnecting chat
#### Fix a reconnecting chat
In this example, every time you press "Toggle theme", the chat re-connects. Why does this happen? Fix the mistake so that the chat re-connects only when you edit Server URL or choose a different the chat room.
@ -1802,7 +1802,7 @@ Sticking to primitive props where possible makes it easier to optimize your comp
</Solution>
### Fix a reconnecting chat, again
#### Fix a reconnecting chat, again
This example connects to the chat either with or without encryption. Toggle the checkbox and notice the different messages in the console when the encryption is on and off. Try changing the room. Then, try toggling the theme. When you're connected to a chat room, you will receive new messages every few seconds. Verify that their color matches the theme you've picked.

8
beta/src/pages/learn/rendering-lists.md

@ -428,7 +428,7 @@ On this page you learned:
<Challenges>
### Splitting a list in two {/*splitting-a-list-in-two*/}
#### Splitting a list in two {/*splitting-a-list-in-two*/}
This example shows a list of all people.
@ -870,7 +870,7 @@ img { width: 100px; height: 100px; border-radius: 50%; }
</Solution>
### Nested lists in one component {/*nested-lists-in-one-component*/}
#### Nested lists in one component {/*nested-lists-in-one-component*/}
Make a list of recipes from this array! For each recipe in the array, display its title as an `<h2>` and list its ingredients in a `<ul>`.
@ -964,7 +964,7 @@ Each of the `recipes` already includes an `id` field, so that's what the outer l
</Solution>
### Extracting a list item component {/*extracting-a-list-item-component*/}
#### Extracting a list item component {/*extracting-a-list-item-component*/}
This `RecipeList` component contains two nested `map` calls. To simplify it, extract a `Recipe` component from it which will accept `id`, `name`, and `ingredients` props. Where do you place the outer `key` and why?
@ -1072,7 +1072,7 @@ Here, `<Recipe {...recipe} key={recipe.id} />` is a syntax shortcut saying "pass
</Solution>
### List with a separator {/*list-with-a-separator*/}
#### List with a separator {/*list-with-a-separator*/}
This example renders a famous haiku by Katsushika Hokusai, with each line wrapped in a `<p>` tag. Your job is to insert an `<hr />` separator between each paragraph. Your resulting structure should look like this:

4
beta/src/pages/learn/responding-to-events.md

@ -540,7 +540,7 @@ Unlike rendering functions, event handlers don't need to be [pure](/learn/keepin
<Challenges>
### Fix an event handler {/*fix-an-event-handler*/}
#### Fix an event handler {/*fix-an-event-handler*/}
Clicking this button is supposed to switch the page background between white and black. However, nothing happens when you click it. Fix the problem. (Don't worry about the logic inside `handleClick`—that part is fine.)
@ -621,7 +621,7 @@ export default function LightSwitch() {
</Solution>
### Wire up the events {/*wire-up-the-events*/}
#### Wire up the events {/*wire-up-the-events*/}
This `ColorSwitch` component renders a button. It's supposed to change the page color. Wire it up to the `onChangeColor` event handler prop it receives from the parent so that clicking the button changes the color.

10
beta/src/pages/learn/reusing-logic-with-custom-hooks.md

@ -1903,7 +1903,7 @@ Sometimes, you don't even need a Hook!
<Challenges>
### Extract a `useCounter` Hook {/*extract-a-usecounter-hook*/}
#### Extract a `useCounter` Hook {/*extract-a-usecounter-hook*/}
This component uses a state variable and an Effect to display a number that increments every second. Extract this logic into a custom Hook called `useCounter`. Your goal is to make the `Counter` component implementation look exactly like this:
@ -1975,7 +1975,7 @@ Notice that `App.js` doesn't need to import `useState` or `useEffect` anymore.
</Solution>
### Make the counter delay configurable {/*make-the-counter-delay-configurable*/}
#### Make the counter delay configurable {/*make-the-counter-delay-configurable*/}
In this example, there is a `delay` state variable controlled by a slider, but its value is not used. Pass the `delay` value to your custom `useCounter` Hook, and change the `useCounter` Hook to use the passed `delay` instead of hardcoding `1000` ms.
@ -2077,7 +2077,7 @@ export function useCounter(delay) {
</Solution>
### Extract `useInterval` out of `useCounter` {/*extract-useinterval-out-of-usecounter*/}
#### Extract `useInterval` out of `useCounter` {/*extract-useinterval-out-of-usecounter*/}
Currently, your `useCounter` Hook does two things. It sets up an interval, and it also increments a state variable on every interval tick. Split out the logic that sets up the interval into a separate Hook called `useInterval`. It should take two arguments: the `onTick` callback, and the `delay`. After this change, your `useCounter` implementation should look like this:
@ -2171,7 +2171,7 @@ Note that there is a bit of a problem with this solution, which you'll solve in
</Solution>
### Fix a resetting interval {/*fix-a-resetting-interval*/}
#### Fix a resetting interval {/*fix-a-resetting-interval*/}
In this example, there are *two* separate intervals.
@ -2341,7 +2341,7 @@ export function useEvent(fn) {
</Solution>
### Implement a staggering movement {/*implement-a-staggering-movement*/}
#### Implement a staggering movement {/*implement-a-staggering-movement*/}
In this example, the `usePointerPosition()` Hook tracks the current pointer position. Try moving your cursor or your finger over the preview area and see the red dot follow your movement. Its position is saved in the `pos1` variable.

8
beta/src/pages/learn/separating-events-from-effects.md

@ -977,7 +977,7 @@ It's possible that in the future, some of these restrictions will be lifted. But
<Challenges>
### Fix a variable that doesn't update {/*fix-a-variable-that-doesnt-update*/}
#### Fix a variable that doesn't update {/*fix-a-variable-that-doesnt-update*/}
This `Timer` component keeps a `count` state variable which increases every second. The value by which it's increasing is stored in the `increment` state variable. You can control the `increment` variable with the plus and minus buttons.
@ -1092,7 +1092,7 @@ Now, when `increment` changes, React will re-synchronize your Effect, which will
</Solution>
### Fix a freezing counter {/*fix-a-freezing-counter*/}
#### Fix a freezing counter {/*fix-a-freezing-counter*/}
This `Timer` component keeps a `count` state variable which increases every second. The value by which it's increasing is stored in the `increment` state variable, which you can control it with the plus and minus buttons. For example, try pressing the plus button nine times, and notice that the `count` now increases by ten (rather than by one) after every next second.
@ -1251,7 +1251,7 @@ Since `onTick` is an Event function, the code inside it isn't reactive. The chan
</Solution>
### Fix a non-adjustable delay {/*fix-a-non-adjustable-delay*/}
#### Fix a non-adjustable delay {/*fix-a-non-adjustable-delay*/}
In this example, you can customize the interval delay. It's stored in a `delay` state variable which is updated by two buttons. However, even if you press the "plus 100 ms" button until the `delay` is 1000 milliseconds (that is, a second), you'll notice that the timer still increments very fast (every 100 ms). It's as if your changes to the `delay` are ignored. Find and fix the bug.
@ -1436,7 +1436,7 @@ In general, you should be suspicious of functions like `onMount` that focus on t
</Solution>
### Fix a delayed notification {/*fix-a-delayed-notification*/}
#### Fix a delayed notification {/*fix-a-delayed-notification*/}
When you join a chat room, this component shows a notification. However, it doesn't show the notification immediately. Instead, the notification is artificially delayed by two seconds so that the user has a chance to look around the UI.

4
beta/src/pages/learn/sharing-state-between-components.md

@ -319,7 +319,7 @@ To see what this feels like in practice with a few more components, read [Thinki
<Challenges>
### Synced inputs {/*synced-inputs*/}
#### 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.
@ -425,7 +425,7 @@ label { display: block; }
</Solution>
### Filtering a list {/*filtering-a-list*/}
#### Filtering a list {/*filtering-a-list*/}
In this example, the `SearchBar` has its own `query` state that controls the text input. Its parent `FilterableList` component displays a `List` of items, but it doesn't take the search query into account.

8
beta/src/pages/learn/state-a-components-memory.md

@ -907,7 +907,7 @@ What if you wanted both galleries to keep their states in sync? The right way to
<Challenges>
### Complete the gallery {/*complete-the-gallery*/}
#### Complete the gallery {/*complete-the-gallery*/}
When you press "Next" on the last sculpture, the code crashes. Fix the logic to prevent the crash. You may do this by adding extra logic to event handler or by disabling the button when the action is not possible.
@ -1217,7 +1217,7 @@ Notice how `hasPrev` and `hasNext` are used *both* for the returned JSX and insi
</Solution>
### Fix stuck form inputs {/*fix-stuck-form-inputs*/}
#### Fix stuck form inputs {/*fix-stuck-form-inputs*/}
When you type into the input fields, nothing appears. It's like the input values are "stuck" with empty strings. The `value` of the first `<input>` is set to always match the `firstName` variable, and the `value` for the second `<input>` is set to always match the `lastName` variable. This is correct. Both inputs have `onChange` event handlers, which try to update the variables based on the latest user input (`e.target.value`). However, the variables don't seem to "remember" their values between re-renders. Fix this by using state variables instead.
@ -1319,7 +1319,7 @@ h1 { margin-top: 10px; }
</Solution>
### Fix a crash {/*fix-a-crash*/}
#### Fix a crash {/*fix-a-crash*/}
Here is a small form that is supposed to let the user leave some feedback. When the feedback is submitted, it's supposed to display a thank-you message. However, it crashes with an error message saying "Rendered fewer hooks than expected". Can you spot the mistake and fix it?
@ -1441,7 +1441,7 @@ In general, these types of mistakes are caught by the [`eslint-plugin-react-hook
</Solution>
### Remove unnecessary state {/*remove-unnecessary-state*/}
#### Remove unnecessary state {/*remove-unnecessary-state*/}
When the button is clicked, this example should ask for the user's name and then display an alert greeting them. You tried to use state to keep the name, but for some reason it always shows "Hello, !".

2
beta/src/pages/learn/state-as-a-snapshot.md

@ -325,7 +325,7 @@ But what if you wanted to read the latest state before a re-render? You'll want
<Challenges>
### Implement a traffic light {/*implement-a-traffic-light*/}
#### Implement a traffic light {/*implement-a-traffic-light*/}
Here is a crosswalk light component that toggles on when the button is pressed:

8
beta/src/pages/learn/synchronizing-with-effects.md

@ -955,7 +955,7 @@ When [Strict Mode](/apis/react/StrictMode) is on, React remounts every component
<Challenges>
### Focus a field on mount {/*focus-a-field-on-mount*/}
#### Focus a field on mount {/*focus-a-field-on-mount*/}
In this example, the form renders a `<MyInput />` component.
@ -1121,7 +1121,7 @@ body {
</Solution>
### Focus a field conditionally {/*focus-a-field-conditionally*/}
#### Focus a field conditionally {/*focus-a-field-conditionally*/}
This form renders two `<MyInput />` components.
@ -1300,7 +1300,7 @@ body {
</Solution>
### Fix an interval that fires twice {/*fix-an-interval-that-fires-twice*/}
#### Fix an interval that fires twice {/*fix-an-interval-that-fires-twice*/}
This `Counter` component displays a counter that should increment every second. On mount, it calls [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval). This causes `onTick` to run every second. The `onTick` function increments the counter.
@ -1427,7 +1427,7 @@ In development, React will still remount your component once to verify that you'
</Solution>
### Fix fetching inside an Effect {/*fix-fetching-inside-an-effect*/}
#### Fix fetching inside an Effect {/*fix-fetching-inside-an-effect*/}
This component shows the biography for the selected person. It loads the biography by calling an asynchronous function `fetchBio(person)` on mount and whenever `person` changes. That asynchronous function returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which eventually resolves to a string. When fetching is done, it calls `setBio` to display that string under the select box.

8
beta/src/pages/learn/updating-arrays-in-state.md

@ -792,7 +792,7 @@ Behind the scenes, Immer always constructs the next state from scratch according
<Challenges>
### Update an item in the shopping cart {/*update-an-item-in-the-shopping-cart*/}
#### Update an item in the shopping cart {/*update-an-item-in-the-shopping-cart*/}
Fill in the `handleIncreaseClick` logic so that pressing "+" increases the corresponding number:
@ -919,7 +919,7 @@ button { margin: 5px; }
</Solution>
### Remove an item from the shopping cart {/*remove-an-item-from-the-shopping-cart*/}
#### Remove an item from the shopping cart {/*remove-an-item-from-the-shopping-cart*/}
This shopping cart has a working "+" button, but the "–" button doesn't do anything. You need to add an event handler to it so that pressing it decreases the `count` of the corresponding product. If you press "–" when the count is 1, the product should automatically get removed from the cart. Make sure it never shows 0.
@ -1080,7 +1080,7 @@ button { margin: 5px; }
</Solution>
### Fix the mutations using non-mutative methods {/*fix-the-mutations-using-non-mutative-methods*/}
#### Fix the mutations using non-mutative methods {/*fix-the-mutations-using-non-mutative-methods*/}
In this example, all of the event handlers in `App.js` use mutation. As a result, editing and deleting todos doesn't work. Rewrite `handleAddTodo`, `handleChangeTodo`, and `handleDeleteTodo` to use the non-mutative methods:
@ -1413,7 +1413,7 @@ ul, li { margin: 0; padding: 0; }
</Solution>
### Fix the mutations using Immer {/*fix-the-mutations-using-immer*/}
#### Fix the mutations using Immer {/*fix-the-mutations-using-immer*/}
This is the same example as in the previous challenge. This time, fix the mutations by using Immer. For your convenience, `useImmer` is already imported, so you need to change the `todos` state variable to use it.

6
beta/src/pages/learn/updating-objects-in-state.md

@ -813,7 +813,7 @@ In practice, you can often "get away" with mutating state in React, but we stron
<Challenges>
### Fix incorrect state updates {/*fix-incorrect-state-updates*/}
#### Fix incorrect state updates {/*fix-incorrect-state-updates*/}
This form has a few bugs. Click the button that increases the score a few times. Notice that it does not increase. Then edit the first name, and notice that the score has suddenly "caught up" with your changes. Finally, edit the last name, and notice that the score has disappeared completely.
@ -961,7 +961,7 @@ The problem with `handleLastNameChange` was that it did not copy the existing `.
</Solution>
### Find and fix the mutation {/*find-and-fix-the-mutation*/}
#### Find and fix the mutation {/*find-and-fix-the-mutation*/}
There is a draggable box on a static background. You can change the box's color using the select input.
@ -1276,7 +1276,7 @@ select { margin-bottom: 10px; }
</Solution>
### Update an object with Immer {/*update-an-object-with-immer*/}
#### Update an object with Immer {/*update-an-object-with-immer*/}
This is the same buggy example as in the previous challenge. This time, fix the mutation by using Immer. For your convenience, `useImmer` is already imported, so you need to change the `shape` state variable to use it.

2
beta/src/pages/learn/writing-markup-with-jsx.md

@ -268,7 +268,7 @@ Now you know why JSX exists and how to use it in components:
<Challenges>
### Convert some HTML to JSX {/*convert-some-html-to-jsx*/}
#### Convert some HTML to JSX {/*convert-some-html-to-jsx*/}
This HTML was pasted into a component, but it's not valid JSX. Fix it:

8
beta/src/pages/learn/you-might-not-need-an-effect.md

@ -795,7 +795,7 @@ In general, whenever you have to resort to writing Effects, keep an eye out for
<Challenges>
### Transform data without Effects {/*transform-data-without-effects*/}
#### Transform data without Effects {/*transform-data-without-effects*/}
The `TodoList` below displays a list of todos. When the "Show only active todos" checkbox is ticked, completed todos are not displayed in the list. Regardless of which todos are visible, the footer displays the count of todos that are not yet completed.
@ -992,7 +992,7 @@ input { margin-top: 10px; }
</Solution>
### Cache a calculation without Effects {/*cache-a-calculation-without-effects*/}
#### Cache a calculation without Effects {/*cache-a-calculation-without-effects*/}
In this example, filtering the todos was extracted into a separate function called `getVisibleTodos()`. This function contains a `console.log()` call inside of it which helps you notice when it's being called. Toggle "Show only active todos" and notice that it causes `getVisibleTodos()` to re-run. This is expected because visible todos change when you toggle which ones to display.
@ -1260,7 +1260,7 @@ This approach satisfies the requirements too. When you type into the input, only
</Solution>
### Reset state without Effects {/*reset-state-without-effects*/}
#### Reset state without Effects {/*reset-state-without-effects*/}
This `EditContact` component receives a contact object with shaped like `{ id, name, email }` as the `savedContact` prop. Try editing the name and email input fields. When you press Save, the contact's button above the form updates to the edited name. When you press Reset, any pending changes in the form are discarded. Play around with this UI to get a feel for it.
@ -1590,7 +1590,7 @@ button {
</Solution>
### Submit a form without Effects {/*submit-a-form-without-effects*/}
#### Submit a form without Effects {/*submit-a-form-without-effects*/}
This `Form` component lets you send a message to a friend. When you submit the form, the `showForm` state variable is set to `false`. This triggers an Effect calling `sendMessage(message)`, which sends the message (you can see it in the console). After the message is sent, you see a "Thank you" dialog with an "Open chat" button that lets you get back to the form.

8
beta/src/pages/learn/your-first-component.md

@ -205,7 +205,7 @@ You've just gotten your first taste of React! Let's recap some key points.
<Challenges>
### Export the component {/*export-the-component*/}
#### Export the component {/*export-the-component*/}
This sandbox doesn't work because the root component is not exported:
@ -257,7 +257,7 @@ You might be wondering why writing `export` alone is not enough to fix this exam
</Solution>
### Fix the return statement {/*fix-the-return-statement*/}
#### Fix the return statement {/*fix-the-return-statement*/}
Something isn't right about this `return` statement. Can you fix it?
@ -324,7 +324,7 @@ img { height: 180px; }
</Solution>
### Spot the mistake {/*spot-the-mistake*/}
#### Spot the mistake {/*spot-the-mistake*/}
Something's wrong with how the `Profile` component is declared and used. Can you spot the mistake? (Try to remember how React distinguishes components from the regular HTML tags!)
@ -396,7 +396,7 @@ img { margin: 0 10px 10px 0; }
</Solution>
### Your own component {/*your-own-component*/}
#### Your own component {/*your-own-component*/}
Write a component from scratch. You can give it any valid name and return any markup. If you're out of ideas, you can write a `Congratulations` component that shows `<h1>Good job!</h1>`. Don't forget to export it!

Loading…
Cancel
Save