The JavaScript you need for React
A quick refresher on the JavaScript React code uses every day: functions, destructuring, spread, map and filter, modules, and async, in live React examples.
- 01Read the JavaScript in a componentName the plain JavaScript behind each part of a typical component: functions, destructuring, map, ternaries, imports, and promises.
- 02Give React new values, not changed onesUse spread, map, and filter to make the new arrays and objects React needs, and say why push and assignment leave the screen behind.
- 03Put values and choices in JSXChoose between a ternary, &&, and ?. inside curly braces, and avoid the 0 that && can show.
Most of a React component is JavaScript
React adds a few things of its own: components, JSX (the markup inside the code), and functions like useState. Everything else in a component is plain JavaScript. This lesson is a quick refresher on the JavaScript that React code uses every day, shown the way React code uses it. It doesn't teach JavaScript from the start: each section links to the JavaScript lesson that does.
Here is a small shop list. Click Add next to Tea, then next to Lemonade.
import { useState } from "react"; const products = [ { id: 1, name: "Tea", price: 3, inStock: true }, { id: 2, name: "Cake", price: 4, inStock: false }, { id: 3, name: "Lemonade", price: 2, inStock: true },]; export default function App() { const [cart, setCart] = useState([]); return ( <> <p>In your cart: {cart.length > 0 ? cart.join(", ") : "nothing yet"}</p> <ul> {products.map(({ id, name, price, inStock }) => ( <li key={id}> {name}, ${price}{" "} {inStock ? ( <button onClick={() => setCart([...cart, name])}>Add</button> ) : ( <em>sold out</em> )} </li> ))} </ul> </> );}The paragraph changes to In your cart: Tea, Lemonade. Now look at which parts of the code are JavaScript:
- Line 1 imports
useStatefrom thereactpackage: a module import. - Lines 3 to 7 are an array of objects: the shop's data.
- Line 9 is a function. A component is a function that returns markup.
- Line 10 uses destructuring to name the two things
useStategives back: the cart, and the function that replaces it. - Line 14 picks one of two texts with a ternary,
? :. - Line 16 turns each product into a list item with map, and takes
id,name,price, andinStockout of each product with destructuring. - Line 20 gives the button an arrow function that makes a new cart with spread.
Only useState and the tags are React. On line 18, the $ before {price} is just a dollar sign in the text; the curly braces put the value of price after it.
useState and the markup come from React.A good cook in a new kitchen only has to learn where things are and how the oven works. The chopping and mixing are the same skills they use anywhere.
- In real life: A new kitchen with its own oven and layout
- In React: React, with components, JSX, and useState
- In real life: Chopping, measuring, and mixing
- In React: Functions, destructuring, spread, map, and ternaries
- In real life: A cook who knows the basics settles in fast
- In React: Someone who knows JavaScript reads React code fast
- In real life: A cook who can't chop struggles in any kitchen
- In React: Gaps in JavaScript show up as React bugs
React code is JavaScript. React gives you components, JSX, and hooks like useState. The rest is JavaScript: functions for components and event handlers, destructuring for props and state, spread to make new copies, map and filter for lists, ternaries and && for choices, modules for files, and promises for data that arrives later.
If any of these feel new, read its JavaScript lesson first. Here they all are:
Components and event handlers are functions
Functions show up in React in two places. A component is a function: React calls it to find out what to show. An event handler is a function too: you hand it to a button, and the browser calls it when someone clicks.
import { useState } from "react"; export default function App() { const [cart, setCart] = useState([]); function handleClear() { setCart([]); } return ( <> <p>Cart: {cart.join(", ") || "empty"}</p> <button onClick={() => setCart([...cart, "Tea"])}>Add tea</button> <button onClick={handleClear}>Clear</button> </> );}Line 3 declares the component, App, with a name that starts with a capital letter. export default lets the file that starts the app import it. Lines 6 to 8 declare another function, handleClear, inside the component.
Line 13 gives the first button an arrow function, () => setCart([...cart, "Tea"]). Nothing runs yet: the arrow only makes a small function, and React calls it on each click. Line 14 hands over handleClear itself, without brackets. Line 12 shows the cart; when it's empty, cart.join(", ") gives an empty string, and || uses "empty" instead. Click Add tea twice, then Clear: the paragraph says Cart: Tea, Tea, then Cart: empty.
The brackets matter. onClick={handleClear} passes the function. onClick={handleClear()} calls it on the spot, while React is drawing the button, and passes whatever it gives back. Here is that mistake with a function that changes state:
import { useState } from "react"; export default function App() { const [cart, setCart] = useState([]); function addItem(name) { setCart([...cart, name]); } return <button onClick={addItem("Tea")}>Add tea ({cart.length})</button>;}Line 10 calls addItem("Tea") while React draws the button. That call sets new state, so React draws again, which calls addItem again, and so on. React stops the loop and shows Too many re-renders. React limits the number of renders to prevent an infinite loop. in place of the result. Press Edit & run and change line 10 to onClick={() => addItem("Tea")}: the button appears, and each click adds one tea.
Arrow functions have one more form you'll see everywhere in React: with no curly braces after the arrow, they give back the expression, so (name) => <li>{name}</li> gives back a list item. You can write components as arrow functions too (const App = () => …); React treats both the same. React's docs, and this course, use function declarations. The JavaScript lessons Function expressions and callbacks and Arrow functions cover both forms.
Destructuring props and state
Destructuring takes values out of an object or an array and names them. React code uses it in two places on almost every page: to read a component's props, and to name what useState gives back.
import { useState } from "react"; function ProductCard({ name, price, onAdd }) { return ( <p> {name}: ${price} <button onClick={onAdd}>Add</button> </p> );} export default function App() { const [count, setCount] = useState(0); return ( <> <p>Items in cart: {count}</p> <ProductCard name="Tea" price={3} onAdd={() => setCount(count + 1)} /> <ProductCard name="Cake" price={4} onAdd={() => setCount(count + 1)} /> </> );}Lines 17 and 18 use ProductCard twice, each with its own name, price, and onAdd. These values are the component's props. React collects them into one object, like { name: "Tea", price: 3, onAdd: … }, and passes it to the function. The curly braces on line 3 take the three props out of that object, so line 6 can use name and price directly.
Line 12 uses the square-bracket form. useState(0) gives back an array of two things: the current value and a function that replaces it. [count, setCount] names them by position. Written out without destructuring, line 12 would be:
const state = useState(0);
const count = state[0];
const setCount = state[1];Line 1 keeps the whole array, and lines 2 and 3 read its first and second items. (It sits inside a component like App, so it has no result of its own.) Click Add on both cards in the result above: the count says Items in cart: 2, because each card's onAdd is the arrow function from App.
Destructuring can also give a missing prop a default: function Greeting({ name, city = "Pune" }) uses "Pune" when no city is passed. Exercise 1 uses it, and the Passing props lesson covers props in full.
Spread makes the new copy React needs
When you give React new state, it compares it with the old state. For an array or an object, it checks whether it's the same one, not whether the items inside changed (the Objects and references lesson explains the difference). So to change an array or object in state, you make a new one. Spread, ..., is the usual way. Click Add lemonade (push) first, then Add juice (copy):
import { useState } from "react"; export default function App() { const [items, setItems] = useState(["Tea", "Cake"]); function addByPush() { items.push("Lemonade"); setItems(items); } function addByCopy() { setItems([...items, "Juice"]); } return ( <> <button onClick={addByPush}>Add lemonade (push)</button> <button onClick={addByCopy}>Add juice (copy)</button> <ul> {items.map((name, index) => ( <li key={index}>{name}</li> ))} </ul> </> );}The first click changes nothing on the screen: the list still shows Tea and Cake. Line 7 pushes Lemonade into the array React already has, and line 8 hands that same array back. React compares old and new, finds the same array, and skips drawing again.
The second click shows four items: Tea, Cake, Lemonade, and Juice. Line 12 builds a new array: ...items copies every item of the old one into it, and "Juice" goes at the end. A new array means new state, so React draws again, and only now shows the Lemonade that line 7 pushed earlier.
push puts Lemonade into the array React already has, and setItems(items) hands back that same array, so React sees nothing new. Right: [...items, "Juice"] builds a new array, and React renders with it.Objects work the same way. Spread copies every field into a new object, and any field you write after it replaces the copied one. Click Move to Pune:
import { useState } from "react"; export default function App() { const [profile, setProfile] = useState({ name: "Asha", city: "Delhi", plan: "Pro" }); return ( <> <p> {profile.name} lives in {profile.city} and has the {profile.plan} plan. </p> <button onClick={() => setProfile({ ...profile, city: "Pune" })}> Move to Pune </button> </> );}Line 4 keeps a profile object in state. Line 11 makes a new object: ...profile copies name, city, and plan, then city: "Pune" replaces the city. The paragraph changes to Asha lives in Pune and has the Pro plan., and the old object is left as it was.
Each row shows one job done both ways. The middle column changes the old value, which React can't see; the right column makes a new value, which is what state needs:
| Job | Changes the old value | Makes a new value |
|---|---|---|
| Add an item | items.push(tea) | [...items, tea] |
| Remove an item | items.splice(index, 1) | items.filter((item) => item.id !== id) |
| Change one item | items[0].quantity = 2 | items.map((item) => (item.id === id ? { ...item, quantity: 2 } : item)) |
| Sort | items.sort() | items.toSorted() or [...items].sort() |
| Change a field | profile.city = "Pune" | { ...profile, city: "Pune" } |
toSorted() is a newer array method that sorts a copy; the Sorting and copying safely lesson covers it. Making new values instead of changing old ones is called immutability, and the Adding interactivity stage has a lesson each on updating objects and updating arrays in state.
map and filter turn data into lists
React has no special loop for showing a list. You turn an array of data into an array of elements with map, and pick which items to show with filter. Type tea in the search box:
import { useState } from "react"; const products = [ { id: 1, name: "Green tea", price: 3 }, { id: 2, name: "Lemon cake", price: 4 }, { id: 3, name: "Iced tea", price: 2 },]; export default function App() { const [query, setQuery] = useState(""); const matches = products.filter((product) => product.name.toLowerCase().includes(query.toLowerCase()), ); return ( <> <input placeholder="Search" value={query} onChange={(event) => setQuery(event.target.value)} /> <ul> {matches.map((product) => ( <li key={product.id}>{product.name}</li> ))} </ul> <p> {matches.length} of {products.length} products </p> </> );}Line 10 keeps the search text in state. Lines 11 to 13 use filter to make a new array, matches, of the products whose name includes that text; toLowerCase() on both sides makes "Tea" match "tea". Line 20 sets the query on every key press with an arrow function that reads event.target.value, the text in the box.
Lines 23 to 25 use map to make one <li> per match. The arrow function has round brackets instead of curly braces after =>, so it gives back the <li> without a return. The key tells React which item is which; the Rendering lists lesson explains it. Line 28 shows two lengths. With tea typed, the list shows Green tea and Iced tea, and the line says 2 of 3 products.
tea in the search box, filter keeps two of the three products, and map turns each one into an <li>. Neither changes products; each makes a new array.Neither filter nor map changes products: each gives back a new array. That's why they are safe to use on state too. reduce, their sibling, adds up a list into one value, like a total; the cart in the practical section uses it.
Ternaries, && and ?. inside JSX
Curly braces in JSX hold an expression: code that gives back a value, like price * 2 or a function call. An if statement isn't an expression, so it can't go inside the braces. Three operators fill the gap: the ternary ? : picks one of two values, && shows something or nothing, and ?. and ?? handle a value that might be missing.
function Product({ name, stock }) { return ( <li> {name}: {stock > 0 ? `${stock} left` : "sold out"} {stock > 0 && stock < 3 && <strong> Hurry!</strong>} </li> );} export default function App() { return ( <ul> <Product name="Tea" stock={5} /> <Product name="Cake" stock={2} /> <Product name="Lemonade" stock={0} /> </ul> );}Line 4 uses a ternary: if stock > 0, it gives back a template literal, `${stock} left`, and otherwise "sold out". Line 5 chains two &&: the <strong> shows only when both conditions are true. The result reads Tea: 5 left, Cake: 2 left Hurry!, and Lemonade: sold out.
Data from a server often has gaps: an order without a customer, a user without an address. Reading a field of null throws an error, and an error while drawing takes the component down. Optional chaining stops in time:
const order = { id: 7, customer: { name: "Asha" } };const guestOrder = { id: 8, customer: null }; function Thanks({ order }) { return <p>Thanks, {order.customer?.name ?? "guest"}!</p>;} export default function App() { return ( <> <Thanks order={order} /> <Thanks order={guestOrder} /> </> );}Line 5 reads order.customer?.name. When customer is null, ?. stops and gives undefined instead of throwing, and ?? swaps in "guest". The result: Thanks, Asha! and Thanks, guest!. Press Edit & run and delete the ? on line 5: the result shows TypeError: Cannot read properties of null (reading 'name').
&& has one surprise. It gives back its left side when that side is falsy, and React shows numbers. Pick 0 below and watch line 7:
const value = 3; export default function App() { return ( <> <p>{value}</p> <p>{value && <strong>yes</strong>}</p> <p>{value ? "yes" : "no"}</p> </> );}3- Line 6
3
3 - Line 7
yes
yes - Line 8
yes
yes
3 is truthy. Line 6 shows the value itself, line 7's && gives back the <strong>, and line 8's ternary picks "yes".
For 0, line 7 shows 0: 0 && … gives back 0, not false. For null, undefined, true, and false, line 6 shows nothing at all, which is why && works for "something or nothing" as long as the left side is a true-or-false test, like count > 0.
How to read the table: each row is something you want to show, what to write inside the curly braces, and why.
| You want | Write | Why |
|---|---|---|
| One of two things | cond ? a : b, a ternary. | It always gives back a value, so it works inside curly braces. |
| Something, or nothing | cond && thing. | When cond is false, && gives back false, which React shows as nothing. |
| A count, or nothing | count > 0 && thing. | With count && thing, a count of 0 gives back 0, and React shows it. |
| A value that may be missing | order.customer?.name ?? "guest". | ?. stops at null instead of throwing, and ?? gives a fallback. |
| An if or a loop | Write it before the return, or use a ternary and map. | Curly braces take expressions only, not statements like if and for. |
The Conditional rendering lesson goes further, with early returns and null.
import and export between files
A React app has many files, usually one component per file, and they share code with import and export. This example has three files in tabs: App.jsx, ProductCard.jsx, and format.js, a plain JavaScript file with no JSX.
import ProductCard from "./ProductCard.jsx";import { formatPrice } from "./format.js"; export default function App() { return ( <> <ProductCard name="Tea" price={3} /> <ProductCard name="Cake" price={4.5} /> <p>Delivery: {formatPrice(2)}</p> </> );}In format.js, line 1 names its export: export function formatPrice. Line 2 builds the text with a template literal: the first $ is a dollar sign, and ${…} puts in the amount with two decimals.
In ProductCard.jsx, line 3 is the file's default export: export default function ProductCard. Line 1 imports formatPrice in curly braces, because it's a named export.
In App.jsx, line 1 imports the default export without braces, and line 2 imports the named one with braces. Both paths start with ./, which means "a file next to this one". A name without it, like "react", means an installed package. The result: Tea: $3.00, Cake: $4.50, and Delivery: $2.00.
Press Edit & run, open the format.js tab, and change the first $ on line 2 to €. All three prices change, in both files that import it. The Your first component lesson moves components into their own files step by step.
Promises and async for data that arrives later
Data from a server doesn't arrive at once. JavaScript represents a result that comes later with a promise, and async and await let you write code that waits for it. Click Load products:
import { useState } from "react"; function fetchProducts() { return new Promise((resolve) => { setTimeout(() => resolve([{ id: 1, name: "Tea" }, { id: 2, name: "Cake" }]), 500); });} export default function App() { const [products, setProducts] = useState(null); const [loading, setLoading] = useState(false); async function handleLoad() { setLoading(true); const list = await fetchProducts(); setProducts(list); setLoading(false); } return ( <> <button onClick={handleLoad} disabled={loading}> {loading ? "Loading…" : "Load products"} </button> <p>Products: {products?.length ?? "not loaded yet"}</p> <ul>{products?.map((product) => <li key={product.id}>{product.name}</li>)}</ul> </> );}Lines 3 to 7 are a stand-in for a server: fetchProducts gives back a promise, and line 5 resolves it with two products after half a second. In a real app it would look like this, with the browser's fetch:
async function fetchProducts() {
const response = await fetch("/api/products");
return response.json();
}(There is no /api/products here to call, so it doesn't run.) Back in the example, line 13 makes the click handler async. Line 14 sets loading, so React draws the button as Loading… and turns it off. Line 15 waits for the promise; await pauses only handleLoad, not the page. When the products arrive, lines 16 and 17 put them in state and turn loading off.
Before the click, products is null. Line 25 reads products?.length, which gives undefined, so ?? shows not loaded yet. Line 26's products?.map(…) also gives undefined, which React shows as nothing. After the click and half a second, the paragraph says Products: 2, with Tea and Cake below.
Here a click starts the loading. Loading data when a component first appears uses an effect, a data library, or a framework; the Fetching data lesson covers them.
A cart page that uses all of it
Real components mix all of these. Here is a cart with quantities, a total, and remove buttons. Click +1 next to Tea, then remove both items.
import { useState } from "react"; const startCart = [ { id: 1, name: "Tea", price: 3, quantity: 1 }, { id: 2, name: "Cake", price: 4, quantity: 2 },]; export default function App() { const [cart, setCart] = useState(startCart); const total = cart.reduce((sum, item) => sum + item.price * item.quantity, 0); function addOne(id) { setCart( cart.map((item) => item.id === id ? { ...item, quantity: item.quantity + 1 } : item, ), ); } function remove(id) { setCart(cart.filter((item) => item.id !== id)); } return ( <> {cart.length === 0 && <p>Your cart is empty.</p>} <ul> {cart.map(({ id, name, quantity }) => ( <li key={id}> {name} × {quantity} <button onClick={() => addOne(id)}>+1</button>{" "} <button onClick={() => remove(id)}>Remove</button> </li> ))} </ul> <p>Total: ${total}</p> </> );}Line 10 adds up the cart with reduce: price times quantity for each item, starting from 0. Tea is 3 × 1 and Cake is 4 × 2, so the total starts at $11. Lines 13 to 17 make a new cart with map: for the item with the clicked id, the ternary on line 15 gives a new object, copied with spread and with one more in quantity; every other item stays as it is. Line 21 removes an item with filter.
Line 26 shows the empty-cart message only when the cart is empty. Line 28 destructures each item in the arrow's parameter, and lines 30 and 31 give each button an arrow that passes its own id. After +1 on Tea, the line says Tea × 2 and the total $14. After removing both items, you see Your cart is empty. and Total: $0.
Practice the most important habit from this lesson: giving state a new value instead of changing the old one.
[...items, "Juice"]items.push("Juice")items.filter((name) => name !== "Tea")items.splice(0, 1)items.map((name) => name.toUpperCase())items.sort(){ ...profile, city: "Pune" }profile.city = "Pune"
Sort each line: does it make a new array or object, or change the one you already have?
Common mix-ups
- "React has its own loops and if statements for markup." No. You use
mapandfilterfor lists and a ternary or&&for choices: plain JavaScript inside curly braces. - "
onClick={save()}hands the button my function." No. The brackets call it while React draws. WriteonClick={save}, oronClick={() => save(item)}to pass something. - "Pushing to the array and calling the set function updates the screen." No. It's the same array, so React skips the update. Make a new array with spread,
map, orfilter. - "
count && …shows nothing when the count is 0." No. It shows0. Writecount > 0 && …. - "Components must be arrow functions", or "must be function declarations". No. Both work; React only needs a function. This course uses
functiondeclarations, like React's docs. - "
awaitfreezes the page until the data arrives." No. It pauses only the async function. The page keeps working, which is how the button can showLoading…while it waits.
Practice exercises
Each exercise is React code that leans on one JavaScript feature. Predict first, then press Edit & run to check, or change the code and watch the result.
What does this page show? Answer first, then press Edit & run to check.
function Greeting({ name, city = "Pune" }) {
return <p>Hi {name} from {city}!</p>;
}
export default function App() {
return <Greeting name="Asha" />;
}function Greeting({ name, city = "Pune" }) { return <p>Hi {name} from {city}!</p>;} export default function App() { return <Greeting name="Asha" />;}Destructuring takes name from the props, "Asha". There is no city prop, so the default "Pune" fills in, and the page shows Hi Asha from Pune!.
Which names does this list show?
const products = [
{ id: 1, name: "Tea", price: 3 },
{ id: 2, name: "Cake", price: 4 },
{ id: 3, name: "Lemonade", price: 2 },
];
export default function App() {
return (
<ul>
{products
.filter((product) => product.price < 4)
.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
}const products = [ { id: 1, name: "Tea", price: 3 }, { id: 2, name: "Cake", price: 4 }, { id: 3, name: "Lemonade", price: 2 },]; export default function App() { return ( <ul> {products .filter((product) => product.price < 4) .map((product) => ( <li key={product.id}>{product.name}</li> ))} </ul> );}filter keeps Tea (3) and Lemonade (2) and drops Cake, because 4 < 4 is false. map then makes one <li> for each, in the same order: Tea, then Lemonade.
Click Add cake in the result: nothing happens. Fix addCake so the list updates. What does it show after one click?
import { useState } from "react"; export default function App() { const [items, setItems] = useState(["Tea"]); function addCake() { items.push("Cake"); setItems(items); } return ( <> <button onClick={addCake}>Add cake</button> <ul> {items.map((name, index) => ( <li key={index}>{name}</li> ))} </ul> </> );}import { useState } from "react"; export default function App() { const [items, setItems] = useState(["Tea"]); function addCake() { setItems([...items, "Cake"]); } return ( <> <button onClick={addCake}>Add cake</button> <ul> {items.map((name, index) => ( <li key={index}>{name}</li> ))} </ul> </> );}[...items, "Cake"] is a new array with Tea and Cake. React sees new state, draws again, and the list shows Tea and Cake.
Press Edit & run: the result shows React's error instead of a button. Fix line 10, then click the button twice. What does it say?
import { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
function addOne() {
setCount(count + 1);
}
return <button onClick={addOne()}>Added: {count}</button>;
}import { useState } from "react"; export default function App() { const [count, setCount] = useState(0); function addOne() { setCount(count + 1); } return <button onClick={addOne}>Added: {count}</button>;}onClick={addOne} passes the function, and React calls it on each click. Two clicks set the count to 1, then 2: Added: 2.
Write addOne so that +1 raises only its own item. What does the Cake line show after one click on Cake's button?
import { useState } from "react"; export default function App() { const [cart, setCart] = useState([ { id: 1, name: "Tea", quantity: 1 }, { id: 2, name: "Cake", quantity: 2 }, ]); function addOne(id) { // Give setCart a new array where only the item with this id has quantity + 1. } return ( <ul> {cart.map((item) => ( <li key={item.id}> {item.name} × {item.quantity}{" "} <button onClick={() => addOne(item.id)}>+1</button> </li> ))} </ul> );}import { useState } from "react"; export default function App() { const [cart, setCart] = useState([ { id: 1, name: "Tea", quantity: 1 }, { id: 2, name: "Cake", quantity: 2 }, ]); function addOne(id) { setCart( cart.map((item) => item.id === id ? { ...item, quantity: item.quantity + 1 } : item, ), ); } return ( <ul> {cart.map((item) => ( <li key={item.id}> {item.name} × {item.quantity}{" "} <button onClick={() => addOne(item.id)}>+1</button> </li> ))} </ul> );}map makes a new array. For Cake, the ternary gives a new object: spread copies id, name, and quantity, then quantity: item.quantity + 1 replaces the quantity. One click on Cake's +1 shows Cake × 3.
Fill in handleLoad so the button loads the reviews. What does the paragraph say after you click and wait?
import { useState } from "react"; function fetchReviews() { return new Promise((resolve) => { setTimeout(() => resolve(["Great tea", "Fresh cake", "Fast delivery"]), 500); });} export default function App() { const [reviews, setReviews] = useState(null); async function handleLoad() { // Wait for fetchReviews(), then put the list it gives back into state. } return ( <> <button onClick={handleLoad}>Load reviews</button> <p>Reviews: {reviews?.length ?? "none yet"}</p> </> );}import { useState } from "react"; function fetchReviews() { return new Promise((resolve) => { setTimeout(() => resolve(["Great tea", "Fresh cake", "Fast delivery"]), 500); });} export default function App() { const [reviews, setReviews] = useState(null); async function handleLoad() { const list = await fetchReviews(); setReviews(list); } return ( <> <button onClick={handleLoad}>Load reviews</button> <p>Reviews: {reviews?.length ?? "none yet"}</p> </> );}await fetchReviews() waits half a second for the three reviews, then setReviews(list) puts them in state. reviews?.length is now 3, so the paragraph says Reviews: 3.
Check your understanding
For each code question, find the JavaScript feature first, then work out what it gives back. Press Edit & run on a question's code to check your answer.
Question 1 of 8What happens with
<button onClick={handleClear()}>?Choose an answer to see the explanation.
Question 2 of 8After one click on Add cake, what does the paragraph show?
Read the code, then predictimport { useState } from "react"; export default function App() { const [items, setItems] = useState(["Tea"]); function addCake() { items.push("Cake"); setItems(items); } return ( <> <button onClick={addCake}>Add cake</button> <p>{items.join(", ")}</p> </> ); }Choose an answer to see the explanation.
Question 3 of 8What does this message line show?
Read the code, then predictconst count = 0; export default function App() { return <p>Messages: {count && <strong>{count} new</strong>}</p>; }Choose an answer to see the explanation.
Question 4 of 8Which line gives React a new profile with a new city?
Choose an answer to see the explanation.
Question 5 of 8What does this greeting show when the order has no customer?
Read the code, then predictconst order = { id: 9, customer: null }; export default function App() { return <p>Hello, {order.customer?.name ?? "guest"}</p>; }Choose an answer to see the explanation.
Question 6 of 8What does this Badge show?
Read the code, then predictfunction Badge({ label, count = 1 }) { return ( <span> {label} ({count}) </span> ); } export default function App() { return <Badge label="New" />; }Choose an answer to see the explanation.
Question 7 of 8ProductCard.jsx declares
export default function ProductCard. Which line in App.jsx imports it?Choose an answer to see the explanation.
Question 8 of 8In the Load products example, what does the button say right after you click it?
Choose an answer to see the explanation.
Key takeaways
- React adds components, JSX, and hooks. The rest of a component is plain JavaScript.
- Components and event handlers are functions. Pass a handler,
onClick={save}, or wrap a call in an arrow; don't call it with(). - Destructuring reads props (
{ name, price }) and names whatuseStategives back. - State needs new arrays and objects. Spread,
map, andfiltermake them;pushand assignment change the old one, and React skips the update. - Curly braces take expressions: a ternary for one of two things,
&&for something or nothing (careful with0), and?.with??for missing data. - Files share components with
importandexport, andasyncfunctionsawaitdata that arrives later.
Remember the one-liner.
React gives you components; JavaScript does the rest, as long as you give React new values instead of changing old ones.
Coming next: How React works: a first look. It follows one click from your component to the screen: render, commit, and paint.