` as a first child. This is why React considers them to represent _the same_ `
`.
+You might expect the state to reset when you tick checkbox, but it doesn't! This is because **both of these `
` tags are rendered at the same position.** React doesn't know where you place the conditions in your function. All it "sees" is the tree you return. In both cases, the `App` component returns a `
` with `
` as a first child. This is why React considers them as _the same_ `
`.
You can think of them as having the same "address": the first child of the first child of the root. This is how React matches them up between the previous and next renders, regardless of how you structure your logic.
@@ -620,7 +618,7 @@ label {
-The counter state gets reset when you click the checkbox. Although you render a `Counter`, the first child of the `div` changes from a `div` to a `section`. When `div` was removed from the DOM, the whole tree below it (including the `Counter` and its state) was destroyed as well.
+The counter state gets reset when you click the checkbox. Although you render a `Counter`, the first child of the `div` changes from a `div` to a `section`. When the child `div` was removed from the DOM, the whole tree below it (including the `Counter` and its state) was destroyed as well.
@@ -921,7 +919,7 @@ Switching between Taylor and Sarah does not preserve the state. This is because
)}
```
-Specifying a `key` tells React to use the `key` itself as part of the position, instead of their order within the parent. This is why, even though you render them in the same place in JSX, from React's perspective, these are two different counters. As a result, they will never share state. Every time a counter appears on screen, its state is created. Every time it is removed, its state is destroyed. Toggling between them resets their state over and over.
+Specifying a `key` tells React to use the `key` itself as part of the position, instead of their order within the parent. This is why, even though you render them in the same place in JSX, from React's perspective, these are two different counters. As a result, they will never share state. Every time a counter appears on the screen, its state is created. Every time it is removed, its state is destroyed. Toggling between them resets their state over and over.
@@ -1170,7 +1168,7 @@ export default function App() {
if (showHint) {
return (
-
Hint: Your favorite movie?
+
Hint: Your favorite city?
{
setShowHint(false);
@@ -1221,7 +1219,7 @@ export default function App() {
return (
{showHint &&
-
Hint: Your favorite movie?
+
Hint: Your favorite city?
}
{showHint ? (
@@ -1267,7 +1265,7 @@ export default function App() {
if (showHint) {
return (
-
Hint: Your favorite movie?
+
Hint: Your favorite city?
{
setShowHint(false);
@@ -1752,7 +1750,7 @@ button {
### Clear an image while it's loading
-When you press "Next", the browser starts loading the next image. However, because it's displayed in the same ` ` tag, by default the browser will keep showing 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.
+When you press "Next", the browser starts loading the next image. However, because it's displayed in the same ` ` 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.
@@ -1765,7 +1763,7 @@ Is there a way to tell React to re-create the DOM instead of reusing it?
```js
import { useState } from 'react';
-export default function ReviewTool() {
+export default function Gallery() {
const [index, setIndex] = useState(0);
const hasNext = index < images.length - 1;
@@ -1777,7 +1775,7 @@ export default function ReviewTool() {
}
}
- let src = images[index];
+ let image = images[index];
return (
<>
@@ -1786,21 +1784,40 @@ export default function ReviewTool() {
Image {index + 1} of {images.length}
-
+
+
+ {image.place}
+
>
);
}
-let images = [
- 'https://placekitten.com/100?image=1',
- 'https://placekitten.com/100?image=2',
- 'https://placekitten.com/100?image=3',
- 'https://placekitten.com/100?image=4',
- 'https://placekitten.com/100?image=5',
- 'https://placekitten.com/100?image=6',
- 'https://placekitten.com/100?image=7',
- 'https://placekitten.com/100?image=8',
-];
+let images = [{
+ place: 'Penang, Malaysia',
+ src: 'https://i.imgur.com/FJeJR8M.jpg'
+}, {
+ place: 'Lisbon, Portugal',
+ src: 'https://i.imgur.com/dB2LRbj.jpg'
+}, {
+ place: 'Bilbao, Spain',
+ src: 'https://i.imgur.com/z08o2TS.jpg'
+}, {
+ place: 'Valparaíso, Chile',
+ src: 'https://i.imgur.com/Y3utgTi.jpg'
+}, {
+ place: 'Schwyz, Switzerland',
+ src: 'https://i.imgur.com/JBbMpWY.jpg'
+}, {
+ place: 'Prague, Czechia',
+ src: 'https://i.imgur.com/QwUKKmF.jpg'
+}, {
+ place: 'Ljubljana, Slovenia',
+ src: 'https://i.imgur.com/3aIiwfm.jpg'
+}];
+```
+
+```css
+img { width: 150px; height: 150px; }
```
@@ -1814,7 +1831,7 @@ You can provide a `key` to the ` ` tag. When that `key` changes, React will
```js
import { useState } from 'react';
-export default function ReviewTool() {
+export default function Gallery() {
const [index, setIndex] = useState(0);
const hasNext = index < images.length - 1;
@@ -1826,7 +1843,7 @@ export default function ReviewTool() {
}
}
- let src = images[index];
+ let image = images[index];
return (
<>
@@ -1835,21 +1852,40 @@ export default function ReviewTool() {
Image {index + 1} of {images.length}
-
+
+
+ {image.place}
+
>
);
}
-let images = [
- 'https://placekitten.com/100?image=1',
- 'https://placekitten.com/100?image=2',
- 'https://placekitten.com/100?image=3',
- 'https://placekitten.com/100?image=4',
- 'https://placekitten.com/100?image=5',
- 'https://placekitten.com/100?image=6',
- 'https://placekitten.com/100?image=7',
- 'https://placekitten.com/100?image=8',
-];
+let images = [{
+ place: 'Penang, Malaysia',
+ src: 'https://i.imgur.com/FJeJR8M.jpg'
+}, {
+ place: 'Lisbon, Portugal',
+ src: 'https://i.imgur.com/dB2LRbj.jpg'
+}, {
+ place: 'Bilbao, Spain',
+ src: 'https://i.imgur.com/z08o2TS.jpg'
+}, {
+ place: 'Valparaíso, Chile',
+ src: 'https://i.imgur.com/Y3utgTi.jpg'
+}, {
+ place: 'Schwyz, Switzerland',
+ src: 'https://i.imgur.com/JBbMpWY.jpg'
+}, {
+ place: 'Prague, Czechia',
+ src: 'https://i.imgur.com/QwUKKmF.jpg'
+}, {
+ place: 'Ljubljana, Slovenia',
+ src: 'https://i.imgur.com/3aIiwfm.jpg'
+}];
+```
+
+```css
+img { width: 150px; height: 150px; }
```
diff --git a/beta/src/pages/learn/reacting-to-input-with-state.md b/beta/src/pages/learn/reacting-to-input-with-state.md
index 545568d1..1873d699 100644
--- a/beta/src/pages/learn/reacting-to-input-with-state.md
+++ b/beta/src/pages/learn/reacting-to-input-with-state.md
@@ -4,7 +4,7 @@ title: Reacting to Input with State
-React uses a declarative model for manipulating UI. This means you describe the different states your component can be in according to different inputs rather than manipulating individual pieces of the UI in response to inputs. This is similar to how designers think about UI.
+React uses a declarative way to manipulate the UI. Instead of manipulating individual pieces of the UI directly, you describe the different states that your component can be in, and switch between them in response to the user input. This is similar to how designers think about the UI.
@@ -18,18 +18,20 @@ React uses a declarative model for manipulating UI. This means you describe the
## How declarative UI compares to imperative
-When you design UI interactions, you probably think about how the UI *changes* in response to user actions. Consider a form that lets the user submit some feedback:
+When you design UI interactions, you probably think about how the UI *changes* in response to user actions. Consider a form that lets the user submit an answer:
* When you type something into a form, the "Submit" button **becomes enabled**.
* When you press "Submit", both form and the button **become disabled**, and a spinner **appears**.
* If the network request succeeds, the form **gets hidden**, and the "Thank you" message **appears**.
* If the network request fails, an error message **appears**, and the form **becomes enabled** again.
-In **imperative programming**, the above corresponds directly to how you implement interaction. You have to write the exact instructions to manipulate the UI depending on what just happened. Another way to think of this: imagine riding next to someone in a car and telling them turn by turn where to go. They don't know where you want to go, they just follow your commands. (And if you get the directions wrong, you end up in the wrong place!) It's called *imperative* because you have to "command" each element, from the spinner to the button, telling the computer *how* to update the UI.
+In **imperative programming**, the above corresponds directly to how you implement interaction. You have to write the exact instructions to manipulate the UI depending on what just happened. Here's another way to think about this: imagine riding next to someone in a car and telling them turn by turn where to go.
-In this example of imperative UI programming, the form is built *without* React. It's made with the built-in browser [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model):
+They don't know where you want to go, they just follow your commands. (And if you get the directions wrong, you end up in the wrong place!) It's called *imperative* because you have to "command" each element, from the spinner to the button, telling the computer *how* to update the UI.
+
+In this example of imperative UI programming, the form is built *without* React. It uses the built-in browser [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model):
@@ -41,7 +43,7 @@ async function handleFormSubmit(e) {
show(loadingMessage);
hide(errorMessage);
try {
- await submitForm();
+ await submitForm(textarea.value);
show(successMessage);
hide(form);
} catch (err) {
@@ -78,15 +80,14 @@ function disable(el) {
el.disabled = true;
}
-function submitForm() {
+function submitForm(answer) {
// Pretend it's hitting the network.
return new Promise((resolve, reject) => {
setTimeout(() => {
- let shouldError = Math.random() > 0.5;
- if (shouldError) {
- reject(new Error('Something went wrong'));
- } else {
+ if (answer.toLowerCase() == 'istanbul') {
resolve();
+ } else {
+ reject(new Error('Good guess but a wrong answer. Try again!'));
}
}, 1500);
});
@@ -110,22 +111,31 @@ textarea.oninput = handleTextareaChange;
```html public/index.html
-Thank you!
+That's right!
+
+
```
-Manipulating the UI works well enough for isolated examples, but it gets exponentially more difficult to manage in more complex systems. Imagine updating a page full of different forms like this one. Adding a new UI element or a new interaction would require carefully checking all existing code to make sure you haven't introduced a bug (for example, forgetting to show or hide something).
+Manipulating the UI imperatively works well enough for isolated examples, but it gets exponentially more difficult to manage in more complex systems. Imagine updating a page full of different forms like this one. Adding a new UI element or a new interaction would require carefully checking all existing code to make sure you haven't introduced a bug (for example, forgetting to show or hide something).
React was built to solve this problem.
-In React, you don't directly manipulate the UI--meaning you don't enable, disable, show, or hide components directly. Instead, you **declare what you want to show**, and React figures out how to update the UI. Think of getting into a taxi and telling the driver where you want to go instead of telling them exactly where to turn. It's the driver's job to get you there, and they might even know some shortcuts you hadn't considered!
+In React, you don't directly manipulate the UI--meaning you don't enable, disable, show, or hide components directly. Instead, you **declare what you want to show**, and React figures out how to update the UI. Think of getting into a taxi and telling the driver where you want to go instead of telling them exactly where to turn. It's the driver's job to get you there, and they might even know some shortcuts you haven't considered!
@@ -141,7 +151,7 @@ You've seen how to implement a form imperatively above. To better understand how
### Step 1: Identify your component's different visual states
-In computer science, you may hear about a ["state machine"](https://en.wikipedia.org/wiki/Finite-state_machine) being in one of several “states”. If you work with a designer, you may have seen visual mockups for different states. Designers work with visual states all the time. React stands at the intersection of design and computer science, so both of these ideas are sources of inspiration.
+In computer science, you may hear about a ["state machine"](https://en.wikipedia.org/wiki/Finite-state_machine) being in one of several “states”. If you work with a designer, you may have seen mockups for different "visual states". React stands at the intersection of design and computer science, so both of these ideas are sources of inspiration.
First, you need to visualize all the different "states" of the UI the user might see:
@@ -156,58 +166,68 @@ Just like a designer, you'll want to "mock up" or create "mocks" for the differe
```js
-export default function FeedbackForm({
+export default function Form({
status = 'empty'
}) {
if (status === 'success') {
- return Thank you!
+ return That's right!
}
return (
-
-
-
-
- Submit
-
-
+ <>
+ City quiz
+
+ In which city is there a billboard that turns air into drinkable water?
+
+
+
+
+
+ Submit
+
+
+ >
)
}
```
-You could call that prop anything you like, the naming is not important. Try editing `status = 'empty'` to `status = 'success'` to see the success message appear. Mocking lets you quickly iterate on the UI before you wire up any logic.
-
-Here is a more fleshed out prototype of the same component, still "controlled" by the `status` prop:
+You could call that prop anything you like, the naming is not important. Try editing `status = 'empty'` to `status = 'success'` to see the success message appear. Mocking lets you quickly iterate on the UI before you wire up any logic. Here is a more fleshed out prototype of the same component, still "controlled" by the `status` prop:
```js
-export default function FeedbackForm({
+export default function Form({
// Try 'submitting', 'error', 'success':
status = 'empty'
}) {
if (status === 'success') {
- return Thank you!
+ return That's right!
}
return (
-
-
-
-
- Submit
-
- {status === 'error' &&
-
- Something went wrong
-
- }
-
+ <>
+ City quiz
+
+ In which city is there a billboard that turns air into drinkable water?
+
+
+
+
+
+ Submit
+
+ {status === 'error' &&
+
+ Good guess but a wrong answer. Try again!
+
+ }
+
+ >
);
}
```
@@ -225,7 +245,7 @@ If a component has a lot of visual states, it can be convenient to show them all
```js App.js active
-import FeedbackForm from './FeedbackForm.js';
+import Form from './Form.js';
let statuses = [
'empty',
@@ -240,8 +260,8 @@ export default function App() {
<>
{statuses.map(status => (
- FeedbackForm ({status}):
-
+ Form ({status}):
+
))}
>
@@ -249,10 +269,10 @@ export default function App() {
}
```
-```js FeedbackForm.js
-export default function FeedbackForm({ status }) {
+```js Form.js
+export default function Form({ status }) {
if (status === 'success') {
- return Thank you!
+ return That's right!
}
return (
@@ -268,7 +288,7 @@ export default function FeedbackForm({ status }) {
{status === 'error' &&
- Something went wrong
+ Good guess but a wrong answer. Try again!
}
@@ -285,7 +305,7 @@ body { margin: 0; }
-Pages like this are often known as "living styleguides" or "storybooks."
+Pages like this are often called "living styleguides" or "storybooks."
@@ -296,17 +316,17 @@ Pages like this are often known as "living styleguides" or "storybooks."
-State changes can generally be triggered from two different sources:
+You can trigger state updates in response to two kinds of inputs:
-* **Human** triggers like clicking a button, typing in a field, navigating a link.
-* **Computer** triggers like a network response arriving, a timeout completing, an image loading.
+* **Human inputs**, like clicking a button, typing in a field, navigating a link.
+* **Computer inputs,** like a network response arriving, a timeout completing, an image loading.
-**All triggers must set [state variables](/learn/state-a-components-memory#anatomy-of-usestate) to update the UI.** For the form you're developing, the following triggers will need to change state:
+In both cases, **you must set [state variables](/learn/state-a-components-memory#anatomy-of-usestate) to update the UI**. For the form you're developing, you will need to change state in response to a few different inputs:
-* **Changing the text input** (human) should switch it from the Empty state to the Typing state or back, depending on whether the text box is empty or not.
-* **Clicking the Submit button** (human) should switch it to the Submitting state.
-* **Successful network response** (computer) should switch it to the Success state.
-* **Failed network response** (computer) should switch it to the Error state with the corresponding error message.
+* **Changing the text input** (human) should switch it from the *Empty* state to the *Typing* state or back, depending on whether the text box is empty or not.
+* **Clicking the Submit button** (human) should switch it to the *Submitting* state.
+* **Successful network response** (computer) should switch it to the *Success* state.
+* **Failed network response** (computer) should switch it to the *Error* state with the matching error message.
> Notice that human inputs often require [event handlers](/learn/responding-to-events)!
@@ -314,18 +334,18 @@ To help visualize this flow, try drawing each state on paper as a labeled circle
-### Step 3: Represent the state in memory using `useState`
+### Step 3: Represent the state in memory with `useState`
-Next you'll need to represent the visual states of your component in memory using `useState`. Simplicity is key: each piece of state is a "moving piece", and **you want as few "moving pieces" as possible**. More complexity leads to more bugs!
+Next you'll need to represent the visual states of your component in memory with [`useState`](/reference/usestate). Simplicity is key: each piece of state is a "moving piece", and **you want as few "moving pieces" as possible**. More complexity leads to more bugs!
-Start with the state that *absolutely must* be there. For example, you'll need to store the `message` for the input, and the `error` (if it exists) to store the last error:
+Start with the state that *absolutely must* be there. For example, you'll need to store the `answer` for the input, and the `error` (if it exists) to store the last error:
```js
-const [message, setMessage] = useState('');
+const [answer, setAnswer] = useState('');
const [error, setError] = useState(null);
```
-Then, you need to store which of the visual states described earlier you want to display. There's usually more than a single way to represent that in memory, so you'll need to experiment with it.
+Then, you'll need a state variable representing which one of the visual states described earlier you want to display. There's usually more than a single way to represent that in memory, so you'll need to experiment with it.
If you struggle to think of the best way immediately, start by adding enough state that you're *definitely* sure that all the possible visual states are covered:
@@ -337,57 +357,57 @@ const [isSuccess, setIsSuccess] = useState(false);
const [isError, setIsError] = useState(false);
```
-Your first idea likely won't be the best, but that's ok—refactoring state is a part of the process!
+Your first idea likely won't be the best, but that's ok--refactoring state is a part of the process!
### Step 4: Remove any non-essential state variables
-You want to avoid duplication in the state content so you're only tracking what is essential. Spending a little time on refactoring your state structure will make your components easier to understand, reduce duplication, and avoid unintended meanings. Your goal is to **prevent the cases where the state in memory doesn't represent any valid UI that you'd want a user to see.** (Like an error message with a disabled input preventing the user from correcting the error!)
+You want to avoid duplication in the state content so you're only tracking what is essential. Spending a little time on refactoring your state structure will make your components easier to understand, reduce duplication, and avoid unintended meanings. Your goal is to **prevent the cases where the state in memory doesn't represent any valid UI that you'd want a user to see.** (For example, you never want to show an error message and disable the input at the same time, or the user won't be able to correct the error!)
-Here are some questions you can ask your state variables:
+Here are some questions you can ask about your state variables:
* **Does this state cause a paradox?** For example, `isTyping` and `isSubmitting` can't both be `true`. A paradox usually means that the state is not constrained enough. There are four possible combinations of two booleans, but only three correspond to valid states. To remove the "impossible" state, you can combine these into a `status` that must be one of three values: `'typing'`, `'submitting'`, or `'success'`.
-* **Is the same information available in another state variable already?** Another paradox: `isEmpty` and `isTyping` can't be `true` at the same time. By making them separate state variables, you're risking that you'll have a bug where they go out of sync. Fortunately, you can remove `isEmpty` and instead check `message.length === 0`.
+* **Is the same information available in another state variable already?** Another paradox: `isEmpty` and `isTyping` can't be `true` at the same time. By making them separate state variables, you risk them going out of sync and causing bugs. Fortunately, you can remove `isEmpty` and instead check `message.length === 0`.
* **Can you get the same information from the inverse of another state variable?** `isError` is not needed because you can check `error !== null` instead.
After this clean-up, you're left with 3 (down from 7!) *essential* state variables:
```js
-const [message, setMessage] = useState('');
+const [answer, setAnswer] = useState('');
const [error, setError] = useState(null);
const [status, setStatus] = useState('typing'); // 'typing', 'submitting', or 'success'
```
-You know they're essential, because you can't remove any of them without breaking the functionality.
+You know they are essential, because you can't remove any of them without breaking the functionality.
-These three variables are a good enough representation of this form's state. However, if we're being pedantic, there are still some intermediate states that don't fully make sense (for example, an `error` only makes sense when `status` is `'typing'`). If you want to model the state even more strictly, consider [extracting it into a reducer](/learn/extracting-state-logic-into-a-reducer) which lets you unify multiple state variables and consolidate the related logic. More on that in the following pages!
+These three variables are a good enough representation of this form's state. However, there are still some intermediate states that don't fully make sense. For example, a non-null `error` doesn't make sense when `status` is `'success'`. To model the state more precisely, you can [extract it into a reducer](/learn/extracting-state-logic-into-a-reducer). Reducers let you unify multiple state variables into a single object and consolidate all the related logic!
-### Step 5: Connect the event handlers to set the state
+### Step 5: Connect the event handlers to set state
-Lastly, create event handlers to set the state variables. Below is the final form in React, with all event handlers wired up:
+Lastly, create event handlers to set the state variables. Below is the final form, with all event handlers wired up:
```js
import { useState } from 'react';
-export default function FeedbackForm() {
- const [message, setMessage] = useState('');
+export default function Form() {
+ const [answer, setAnswer] = useState('');
const [error, setError] = useState(null);
const [status, setStatus] = useState('typing');
if (status === 'success') {
- return Thank you!
+ return That's right!
}
async function handleSubmit(e) {
e.preventDefault();
setStatus('submitting');
try {
- await submitForm();
+ await submitForm(answer);
setStatus('success');
} catch (err) {
setStatus('typing');
@@ -396,39 +416,45 @@ export default function FeedbackForm() {
}
function handleTextareaChange(e) {
- setMessage(e.target.value);
+ setAnswer(e.target.value);
}
return (
-
-
-
-
- Submit
-
- {error !== null &&
-
- {error.message}
-
- }
-
+ <>
+ City quiz
+
+ In which city is there a billboard that turns air into drinkable water?
+
+
+
+
+
+ Submit
+
+ {error !== null &&
+
+ {error.message}
+
+ }
+
+ >
);
}
-function submitForm() {
+function submitForm(answer) {
// Pretend it's hitting the network.
return new Promise((resolve, reject) => {
setTimeout(() => {
- let shouldError = Math.random() > 0.5;
+ let shouldError = answer.toLowerCase() !== 'lima'
if (shouldError) {
- reject(new Error('Something went wrong'));
+ reject(new Error('Good guess but a wrong answer. Try again!'));
} else {
resolve();
}
@@ -453,7 +479,7 @@ Although this code is longer than the original imperative example, it is much le
2. Determine the human and computer triggers for state changes.
3. Model the state with `useState`.
4. Remove non-essential state to avoid bugs and paradoxes.
- 5. Connect the event handlers to set the state.
+ 5. Connect the event handlers to set state.
@@ -463,20 +489,20 @@ Although this code is longer than the original imperative example, it is much le
### Add and remove a CSS class
-Make it so that clicking on the kitten *removes* the `background--active` class from the outer div, but *adds* the `kitten--active` class to the image. Clicking the background again should restore the original CSS classes.
+Make it so that clicking on the picture *removes* the `background--active` CSS class from the outer ``, but *adds* the `picture--active` class to the `
`. Clicking the background again should restore the original CSS classes.
-Visually, you should expect that clicking on the image removes the yellow background and highlights the image border. Clicking outside the image highlights the background, but removes the image border highlight.
+Visually, you should expect that clicking on the picture removes the purple background and highlights the picture border. Clicking outside the picture highlights the background, but removes the picture border highlight.
```js
-export default function Kitten() {
+export default function Picture() {
return (
);
@@ -496,17 +522,17 @@ body { margin: 0; padding: 0; height: 250px; }
}
.background--active {
- background: #ffa;
+ background: #a6b5ff;
}
-.kitten {
- width: 100px;
- height: 100px;
+.picture {
+ width: 200px;
+ height: 200px;
border-radius: 10px;
}
-.kitten--active {
- border: 5px solid gold;
+.picture--active {
+ border: 5px solid #a6b5ff;
}
```
@@ -516,8 +542,8 @@ body { margin: 0; padding: 0; height: 250px; }
This component has two visual states: when the image is active, and when the image is inactive:
-* When the image is active, the CSS classes are `background` and `kitten kitten--active`.
-* When the image is inactive, the CSS classes are `background background--active` and `kitten`.
+* When the image is active, the CSS classes are `background` and `picture picture--active`.
+* When the image is inactive, the CSS classes are `background background--active` and `picture`.
A single boolean state variable is enough to remember whether the image is active. The original task was to remove or add CSS classes. However, in React you need to *describe* what you want to see rather than *manipulate* the UI elements. So you need to calculate both CSS classes based on the current state. You also need to [stop the propagation](/learn/responding-to-events#stopping-propagation) so that clicking the image doesn't register as a click on the background.
@@ -528,13 +554,13 @@ Verify that this version works by clicking the image and then outside of it:
```js
import { useState } from 'react';
-export default function Kitten() {
+export default function Picture() {
const [isActive, setIsActive] = useState(false);
let backgroundClassName = 'background';
- let kittenClassName = 'kitten';
+ let pictureClassName = 'picture';
if (isActive) {
- kittenClassName += ' kitten--active';
+ pictureClassName += ' picture--active';
} else {
backgroundClassName += ' background--active';
}
@@ -549,9 +575,9 @@ export default function Kitten() {
e.stopPropagation();
setIsActive(true);
}}
- className={kittenClassName}
- alt="Kitten"
- src="https://placekitten.com/100"
+ className={pictureClassName}
+ alt="Rainbow houses in Kampung Pelangi, Indonesia"
+ src="https://i.imgur.com/5qwVYb1.jpeg"
/>
);
@@ -571,18 +597,18 @@ body { margin: 0; padding: 0; height: 250px; }
}
.background--active {
- background: #ffa;
+ background: #a6b5ff;
}
-.kitten {
- width: 100px;
- height: 100px;
+.picture {
+ width: 200px;
+ height: 200px;
border-radius: 10px;
border: 5px solid transparent;
}
-.kitten--active {
- border: 5px solid gold;
+.picture--active {
+ border: 5px solid #a6b5ff;
}
```
@@ -595,7 +621,7 @@ Alternatively, you could return two separate chunks of JSX:
```js
import { useState } from 'react';
-export default function Kitten() {
+export default function Picture() {
const [isActive, setIsActive] = useState(false);
if (isActive) {
return (
@@ -604,9 +630,9 @@ export default function Kitten() {
onClick={() => setIsActive(false)}
>
);
@@ -614,9 +640,9 @@ export default function Kitten() {
return (
setIsActive(true)}
/>
@@ -637,18 +663,18 @@ body { margin: 0; padding: 0; height: 250px; }
}
.background--active {
- background: #ffa;
+ background: #a6b5ff;
}
-.kitten {
- width: 100px;
- height: 100px;
+.picture {
+ width: 200px;
+ height: 200px;
border-radius: 10px;
border: 5px solid transparent;
}
-.kitten--active {
- border: 5px solid gold;
+.picture--active {
+ border: 5px solid #a6b5ff;
}
```
@@ -730,22 +756,22 @@ lastNameInput.oninput = handleLastNameChange;
First name:
- Bugs
+ Jane
Last name:
- Bunny
+ Jacobs
Edit Profile
- Hello, Bugs Bunny!
+ Hello, Jane Jacobs!