You do not need to be a JavaScript expert to start React, but you do need to read a handful of modern features without blinking. Almost every React component uses them. This lesson reviews exactly those. If any part is new, run the examples and change them; each takes a minute. The editors run React code, so values are shown on the page with a tiny component: that is already the pattern you will use all course.
const and let
Declare variables with const when they will not be reassigned, and let when they will. Avoid the old var. In React code you will write const most of the time.
function App() {
const price = 200; // cannot be reassigned
let quantity = 2; // can be reassigned
quantity = quantity + 1;
const total = price * quantity;
const user = { name: "Asha" };
user.name = "Ravi"; // allowed: const stops reassignment, not changes inside the object
return <p>{quantity} items, total {total}, user {user.name}</p>;
}
export default App;3 items, total 600, user Raviconst does not make an object or array unchangeable: it only stops you pointing the name at something else. React nevertheless asks you to treat data as read-only, and later lessons show how to update objects and arrays by making copies.
Functions and arrow functions
A function can be written in two common ways. The arrow form is shorter and is used everywhere in React for small functions, especially callbacks:
function add(a, b) {
return a + b;
}
const addArrow = (a, b) => a + b; // one expression: the value is returned automatically
const square = n => n * n; // one parameter: brackets are optional
const greet = name => { // a block body needs an explicit return
const message = "Hello, " + name;
return message;
};
function App() {
return <p>{add(2, 3)} {addArrow(4, 5)} {square(6)} {greet("Asha")}</p>;
}
export default App;5 9 36 Hello, AshaTwo details trip beginners. When an arrow function returns an object literal, wrap it in brackets: () => ({ a: 1 }), because curly braces alone start a function body. And functions can be passed around like any value, which is how event handlers and map callbacks work.
Template literals
Backticks create strings that can contain expressions and span lines. You will use them for class names, messages and URLs.
function App() {
const name = "Asha";
const items = 3;
const message = `Hello ${name}, you have ${items} item${items === 1 ? "" : "s"}.`;
return <p>{message}</p>;
}
export default App;Hello Asha, you have 3 items.Objects and arrays
Objects hold named values, arrays hold ordered lists. Their items can be anything, including other objects and arrays: a list of users is an array of objects. Access with dot or bracket notation:
const users = [
{ id: 1, name: "Asha", skills: ["HTML", "CSS"] },
{ id: 2, name: "Ravi", skills: ["PHP"] },
];
function App() {
const first = users[0];
return (
<p>
{first.name} knows {first.skills.length} things; the last is {first.skills[first.skills.length - 1]}.
There are {users.length} users.
</p>
);
}
export default App;Asha knows 2 things; the last is CSS. There are 2 users.Destructuring
Destructuring unpacks values from objects and arrays into variables. React uses it constantly, for example to read props and to receive the pair that useState returns.
function App() {
const user = { name: "Asha", age: 30, city: "Pune" };
const { name, city } = user; // object: matched by property name
const { age: years } = user; // rename while unpacking
const [first, second, ...rest] = [10, 20, 30, 40]; // array: matched by position
return <p>{name} from {city}, {years} years. {first} {second} then {rest.join(",")}</p>;
}
export default App;Asha from Pune, 30 years. 10 20 then 30,40You can destructure in a function's parameter list too: function Greeting({ name, city }) takes an object and pulls out two properties. That is exactly what a React component does with its props.
The spread operator
... copies the items of an array or the properties of an object into a new one. It is the main tool for "changing" data without modifying the original:
function App() {
const original = { name: "Asha", city: "Pune" };
const moved = { ...original, city: "Delhi" }; // copy, then override one property
const list = [1, 2, 3];
const longer = [...list, 4]; // copy and add at the end
const merged = [0, ...list, ...[8, 9]];
return (
<p>
original city: {original.city}; copy city: {moved.city}; list: {list.join(",")};
longer: {longer.join(",")}; merged: {merged.join(",")}
</p>
);
}
export default App;original city: Pune; copy city: Delhi; list: 1,2,3; longer: 1,2,3,4; merged: 0,1,2,3,8,9The original objects stayed unchanged. Remember this pattern: to update something in React, make a new copy with the change. The lessons on state build on it.
map, filter and reduce
These array methods transform data without changing the original array. They are how React turns a list of data into a list of elements.
function App() {
const prices = [120, 80, 45, 200];
const doubled = prices.map(p => p * 2); // one result per item
const cheap = prices.filter(p => p < 100); // keep items that pass a test
const total = prices.reduce((sum, p) => sum + p, 0); // combine into one value
const first = prices.find(p => p > 100); // first match, or undefined
const any = prices.some(p => p > 150); // is there at least one?
return (
<ul>
<li>doubled: {doubled.join(", ")}</li>
<li>cheap: {cheap.join(", ")}</li>
<li>total: {total}</li>
<li>first over 100: {first}</li>
<li>any over 150: {String(any)}</li>
<li>original unchanged: {prices.join(", ")}</li>
</ul>
);
}
export default App;doubled: 240, 160, 90, 400
cheap: 80, 45
total: 445
first over 100: 120
any over 150: true
original unchanged: 120, 80, 45, 200Prefer these over for loops in React code. map in particular is the engine behind rendering lists.
Optional chaining and nullish coalescing
Real data is often missing. ?. stops safely instead of throwing an error when something is null or undefined, and ?? supplies a default only for null or undefined (unlike ||, which also replaces 0 and the empty string).
function App() {
const user = { profile: null, visits: 0 };
const city = user.profile?.city; // undefined, no error
const shown = user.profile?.city ?? "unknown";
const visits = user.visits ?? 10; // keeps 0
const wrong = user.visits || 10; // replaces 0 with 10
return <p>{String(city)} / {shown} / {visits} / {wrong}</p>;
}
export default App;undefined / unknown / 0 / 10Logical && and the ternary
Because JSX is an expression, you will use condition && value and condition ? a : b to decide what to show:
function App() {
const loggedIn = true;
const count = 0;
return (
<div>
<p>{loggedIn ? "Welcome back" : "Please sign in"}</p>
<p>{loggedIn && "You are signed in"}</p>
<p>Messages: {count && "unread"}</p>
</div>
);
}
export default App;Welcome back
You are signed in
Messages: 0Look at the last line: 0 && "unread" evaluates to 0, and React renders the number 0. This surprises everyone once. Use count > 0 && ... so the left side is a real boolean.
Modules: import and export
Real projects split code into files. Each file is a module. A file shares things with export and another file uses them with import:
// math.js
export const PI = 3.14159; // named export
export function double(n) { return n * 2; }
export default function add(a, b) { return a + b; } // one default export per file
// app.js
import add, { PI, double } from "./math.js"; // default first (any name), then named in braces
import { double as twice } from "./math.js"; // rename with "as"
import * as math from "./math.js"; // everything as one objectReact components follow the same rule: a component file normally has one export default for the main component. Local files need a path starting with ./ or ../; packages like React are imported by name: import { useState } from "react";. The live editor lets you write import lines for React only, because it has just one file.
Promises and async/await
Fetching data takes time, so browser functions like fetch return a promise: a value that will arrive later. async/await lets you write the waiting code in a straight line:
async function loadUser() {
const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
const user = await response.json();
return user.name;
}
loadUser().then(name => console.log(name));You will use this in the lesson on fetching data. For now, remember that await can only be used inside an async function and that errors are caught with try/catch.
Common mistakes
- Using
varor reassigningconstvariables, which causes errors or confusing scope. - Forgetting the brackets when an arrow function returns an object literal.
- Using
||for defaults when0or""are valid values; use??. - Changing an array or object in place (
push, assigning a property) when you should make a copy. - Importing a default export with braces, or a named export without them.
- Writing
{list.length && <List />}, which renders0for an empty list.
Exercise
- In the destructuring example, add a
countryproperty touser, unpack it, and show it in the paragraph. - In the map and filter example, add a
Math.max(...prices)line to show the largest price (spread into a function call). - Make
movedalso changename, keepingoriginalintact. - Write a ternary that shows "item" or "items" depending on a
countconstant, and test it with 1 and 2.
Key points
- Use const by default and let when a variable must be reassigned; avoid var.
- Arrow functions, template literals, destructuring and the spread operator appear in nearly every React component.
- map, filter and reduce turn arrays into new arrays and values without changing the original, which is exactly how React wants you to handle data.
- import and export split code into files; a file can have one default export and many named exports.