Modern JavaScript for React
Learn the JavaScript that React code uses on every line: const and let, arrow functions, template literals, destructuring, spread, map/filter/find/reduce, modules, conditional expressions and async/await. You will run every example with Node.js on Brew & Bean menu data.
Most beginners who struggle with React are actually struggling with JavaScript. A React component is just a JavaScript function, and the same ten or so language features appear in almost every file. Learn them here, in plain Node.js scripts, and React will feel much easier.
You will write five small scripts that work with the Brew & Bean coffee shop menu. Prerequisites: you have written a little code in any language (variables, functions, if/else, loops). You need Node.js installed (the LTS version from nodejs.org) and a code editor.
Set up
- 1Install Node.js LTS from https://nodejs.org and accept the defaults.
- 2Open a terminal and run
node --version. You should see a version number such asv22.x.xor newer. - 3Create a folder called
js-practiceand open it in VS Code. - 4You will create files ending in
.mjs. That extension tells Node to treat the file as a modern ES module, soimportandexportwork without any configuration. In a Vite React project, the same code lives in.jsand.jsxfiles.
1. Variables, functions and strings
export const menu = [
{ id: "espresso", name: "Espresso", category: "coffee", price: 120 },
{ id: "cappuccino", name: "Cappuccino", category: "coffee", price: 180 },
{ id: "cold-brew", name: "Cold Brew", category: "coffee", price: 220 },
{ id: "filter-coffee", name: "Filter Coffee", category: "coffee", price: 80 },
{ id: "masala-chai", name: "Masala Chai", category: "tea", price: 90 },
{ id: "croissant", name: "Butter Croissant", category: "bakery", price: 150 },
{ id: "banana-bread", name: "Banana Bread", category: "bakery", price: 130 },
{ id: "veg-sandwich", name: "Veg Grilled Sandwich", category: "food", price: 160 },
];
export function formatPrice(amount) {
return `₹${amount}`;
}The menu is an array of objects. export makes menu and formatPrice available to other files. You will reuse this exact data in the React lessons.
const shopName = "Brew & Bean";
let openOrders = 0;
openOrders = openOrders + 1;
const greet = (name) => `Welcome to ${shopName}, ${name}!`;
const double = (n) => n * 2;
console.log(greet("Priya"));
console.log(double(openOrders));
const item = { id: "cappuccino", name: "Cappuccino", price: 180 };
const { name, price } = item;
console.log(`${name} costs ₹${price}`);
const [first, second] = ["espresso", "cappuccino", "cold-brew"];
console.log(first, second);
const discounted = { ...item, price: 150 };
console.log(item.price, discounted.price);
const cart = ["espresso"];
const newCart = [...cart, "croissant"];
console.log(cart, newCart);Run it with node basics.mjs.
Welcome to Brew & Bean, Priya!
2
Cappuccino costs ₹180
espresso cappuccino
180 150
[ 'espresso' ] [ 'espresso', 'croissant' ]What each feature is and where React uses it
| Feature | Example | In React |
|---|---|---|
const / let | const shopName = ... | Use const by default; let only when you reassign. Never var |
| Arrow function | (name) => ... | Components, event handlers and callbacks |
| Template literal | ` ₹${price} ` | Building text and class names |
| Object destructuring | const { name, price } = item | Reading props: function MenuCard({ name, price }) |
| Array destructuring | const [first, second] = [...] | const [count, setCount] = useState(0) |
| Object spread | { ...item, price: 150 } | Updating state without changing the original |
| Array spread | [...cart, "croissant"] | Adding to a list in state |
Look closely at the last two lines of output. item.price is still 180 and cart still has one element. Spread creates a new object or array with the change, and leaves the original untouched. This is called an immutable update, and React depends on it: React notices a change by comparing the old and new object, so you must create a new one rather than edit the old one in place. You will rely on this in *State and events*.
2. Array methods: map, filter, find, reduce
In React you rarely write for loops. You transform arrays with methods that take a function and return a new value. map turns every element into something else (in React: data into elements on screen). filter keeps the elements that pass a test. find returns the first match. reduce combines all elements into one value, such as a total.
import { menu, formatPrice } from "./menu.mjs";
const names = menu.map((item) => item.name);
console.log(names);
const coffees = menu.filter((item) => item.category === "coffee");
console.log(coffees.length);
const chai = menu.find((item) => item.id === "masala-chai");
console.log(chai.name, formatPrice(chai.price));
const cart = [
{ item_id: "cappuccino", qty: 2 },
{ item_id: "croissant", qty: 1 },
];
const total = cart.reduce((sum, line) => {
const item = menu.find((m) => m.id === line.item_id);
return sum + item.price * line.qty;
}, 0);
console.log("Total:", formatPrice(total));
const updated = cart.map((line) =>
line.item_id === "cappuccino" ? { ...line, qty: line.qty + 1 } : line
);
console.log(cart[0].qty, updated[0].qty);
const withoutCroissant = cart.filter((line) => line.item_id !== "croissant");
console.log(withoutCroissant);Run it with node arrays.mjs. The import line loads the menu from the file you wrote first; the ./ means "in this folder".
[
'Espresso',
'Cappuccino',
'Cold Brew',
'Filter Coffee',
'Masala Chai',
'Butter Croissant',
'Banana Bread',
'Veg Grilled Sandwich'
]
4
Masala Chai ₹90
Total: ₹510
2 3
[ { item_id: 'cappuccino', qty: 2 } ]The total is 2 x ₹180 + 1 x ₹150 = ₹510. reduce starts with 0 (the second argument), and for each line adds price times quantity to the running sum.
The last two operations are the patterns you will write again and again for a cart in React. To change one item, map over the array and return a new object for the matching item and the same object for the rest. To remove one, filter it out. Both leave cart unchanged.
Arrow function return rules
(x) => x * 2 returns x * 2 automatically because there are no braces. With braces, (x) => { return x * 2; }, you must write return. A classic bug is (x) => { x * 2 }, which returns undefined. To return an object without braces, wrap it in parentheses: (x) => ({ id: x }).
3. Conditional expressions
Inside JSX you can only write expressions (things that produce a value), not statements such as if. So React code uses the ternary operator, &&, ?? and ?. constantly.
const cartCount = 0;
const label = cartCount > 0 ? `Cart (${cartCount})` : "Cart is empty";
console.log(label);
const isOpen = true;
console.log(isOpen && "We're open!");
console.log(cartCount && "You have items");
const order = { id: 42, customer: { name: "Arjun" } };
console.log(order.customer?.name);
console.log(order.payment?.method);
console.log(order.note ?? "No note");
console.log(0 || 50, 0 ?? 50);Run it with node conditions.mjs.
Cart is empty
We're open!
0
Arjun
undefined
No note
50 0Operators to know
| Operator | Meaning | Watch out for |
|---|---|---|
a ? b : c | If a, then b, otherwise c | Nesting more than one level gets hard to read |
a && b | If a is truthy, gives b; otherwise gives a | 0 && ... gives 0, and React will print that 0 on screen |
a ?? b | b only if a is null or undefined | Keeps 0 and "" as real values |
a?.b | Reads b only if a exists; otherwise undefined | Hides bugs if you use it everywhere |
a || b | b if a is falsy (0, "", null, undefined, false, NaN) | Replaces a real 0 with the fallback |
The 0 on screen bug
cartCount && <Badge /> renders a literal 0 when the cart is empty, because && returns its left side when that side is falsy. Write cartCount > 0 && <Badge /> instead, so the left side is always true or false.
4. Async code: promises and async/await
Loading data from a server takes time. JavaScript does not stop and wait; it starts the request and carries on, and a promise represents the value that will arrive later. await (allowed inside an async function, or at the top level of a module) pauses that function until the promise settles, which makes async code read top to bottom. Wrap it in try/catch to handle failures.
import { menu } from "./menu.mjs";
function fetchMenu() {
return new Promise((resolve) => {
setTimeout(() => resolve(menu), 1000);
});
}
async function showMenu() {
console.log("Loading menu...");
try {
const items = await fetchMenu();
console.log(`Loaded ${items.length} items`);
} catch (error) {
console.error("Could not load menu:", error.message);
}
}
showMenu();
console.log("This line runs before the menu loads");fetchMenu pretends to be a slow server: it resolves with the menu after one second.
Loading menu...
This line runs before the menu loads
Loaded 8 itemsThe order surprises most beginners. showMenu() runs until the first await, then hands control back, so the last line prints before the menu arrives. This is why a React component must show a "Loading..." state first and update when the data arrives.
In real apps you load data with the built-in fetch function, which works in browsers and in Node 18 and later. The script below calls JSONPlaceholder, a free public test API.
async function loadUser(id) {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const user = await response.json();
return user;
}
const user = await loadUser(1);
console.log(user.name, "-", user.email);Prints a name and email from the test API. fetch does not throw on a 404 or 500 response, so checking response.ok yourself is essential. Using this inside React is covered in *useEffect and fetching data*.
5. Modules: import and export
Every React file is a module. There are two kinds of export, and mixing them up is a frequent beginner error.
A named export (export const menu = ...) is imported with braces and the exact name: import { menu } from "./menu.mjs". A default export (export default function App() {...}) is one per file and is imported without braces, under any name: import App from "./App.jsx". React's own hooks are named exports: import { useState } from "react".
I'm learning JavaScript before React. Explain this line step by step, as if I know basic programming but not modern JavaScript:
[paste one line or a few lines of code]
1. Name each JavaScript feature used (for example destructuring, spread, arrow function).
2. Show the same code written the long way, without those features.
3. Give one small example input and the exact output.What to expect: Run the AI's "long way" version and the original with Node and check they print the same thing. If they don't, ask the AI why.
Try it: Cart helpers
Create cart.mjs. Import menu and formatPrice, and write these functions without changing their input arrays:
1. addToCart(cart, itemId): if the item is already in the cart, increase its qty by 1; otherwise add { item_id: itemId, qty: 1 }.
2. removeFromCart(cart, itemId): remove that line.
3. cartTotal(cart): return the total in rupees.
Test: start with [], add espresso twice and banana-bread once, and print formatPrice(cartTotal(cart)).
Key takeaways
- Use
constby default andletonly when you reassign; avoidvar. - Destructuring and spread appear in almost every React file: props,
useState, and immutable updates. map,filter,findandreducereplace most loops and return new values without changing the original array.- Use ternaries,
&&,??and?.for conditions inside expressions; beware0 && .... async/awaitmakes asynchronous code readable;fetchneeds aresponse.okcheck andtry/catch.- Named exports are imported with braces and the exact name; a default export is imported without braces.
Check yourself
Finishing the quiz marks the lesson as done.
1. const cart = ["espresso"]; const next = [...cart, "chai"]; What are cart and next afterwards?
2. What does menu.filter((item) => item.price < 100) return for the Brew & Bean menu?
3. const items = []; In React, {items.length && <p>You have items</p>} shows what when the array is empty?
4. Which line correctly imports a default export App and a named export formatPrice?
5. const show = (x) => { x * 2 }; What does show(5) return?
6. Why must you check response.ok after await fetch(url)?
Saved on this device. Create a free account to keep it on every device.
Practise this with Sam
A real mock interview, out loud, with an honest scorecard. Free to start.