Loading...
Loading...
Build UIs from components. The library that changed how we think about frontends.
Module 12 · Path to Frameworks
Frameworks like React and Next.js build on JavaScript fundamentals. Node.js runs JavaScript on servers, npm manages packages, and build tools prepare code for production. This module bridges vanilla JS to the modern ecosystem.
Learn Introduction to React in JavaScript — covering Why React, Components & JSX, Props, State with interactive visual examples and step-by-step explanations.
Vanilla JavaScript teaches you how the language works. Frameworks like React teach you how teams ship user interfaces at scale. This module bridges the gap — showing how the fundamentals you have learned map directly to React components, Node.js servers, and npm workflows.
You do not need to pick a framework on day one, but understanding how JavaScript powers React, Next.js, and Node.js makes every future tutorial easier to follow.
Understanding introduction to react is essential for every JavaScript developer. It shows up in frontend UI code, backend APIs, and framework internals — and getting it wrong leads to bugs that are hard to trace. This chapter builds intuition with visuals so the behavior sticks.
Declarative UI, component reuse, and a massive ecosystem.
// The problem React solves: // Vanilla JS: you tell the DOM WHAT TO DO (imperative) document.querySelector(".count").textContent = count; document.querySelector(".btn").addEventListener("click", ...); // You manage every DOM update manually. Complex UIs = spaghetti. // React: you describe WHAT IT SHOULD LOOK LIKE (declarative) function Counter() { const [count, setCount] = useState(0); return ( <div> <p>{count}</p> <button onClick={() => setCount(count + 1)}>+</button> </div> ); } // React figures out what DOM changes are needed. // React's mental model: // UI = f(state) // Your UI is a function of your data. // When data changes → React re-renders → DOM updates. // Why React dominates: // - Component model (reusable UI pieces) // - Declarative (describe what, not how) // - Virtual DOM (efficient updates) // - Massive ecosystem (Next.js, React Native, etc.) // - Job market (most in-demand frontend skill) // Setup: // $ pnpm create vite my-app --template react-ts // $ cd my-app && pnpm install && pnpm dev
Functions that return UI. JSX makes HTML-in-JS natural.
// A component is just a function that returns JSX: function Greeting() { return <h1>Hello, World!</h1>; } // JSX looks like HTML but it's JavaScript: // <h1>Hello</h1> compiles to: // React.createElement("h1", null, "Hello") // JSX rules: // 1. Return ONE root element (or use Fragment <>...</>) function Card() { return ( <> {/* Fragment — no extra DOM node */} <h2>Title</h2> <p>Content</p> </> ); } // 2. Close all tags (even self-closing) // <img src="..." /> ← not <img src="..."> // <br /> ← not <br> // 3. className instead of class // <div className="container"> ← not class="container" // 4. JavaScript expressions in curly braces: const name = "Alice"; const element = <h1>Hello, {name}!</h1>; const math = <p>{2 + 2}</p>; // renders: 4
Components are functions returning JSX. JSX is syntactic sugar over React.createElement — it's JavaScript, not HTML.
Pass data from parent to child. One-way data flow.
// Props = arguments to your component function: function Button({ label, onClick, variant = "primary" }) { return ( <button className={variant} onClick={onClick}> {label} </button> ); } // Using it: <Button label="Save" onClick={handleSave} variant="primary" /> <Button label="Cancel" onClick={handleCancel} variant="secondary" /> // Props are READ-ONLY — never modify them: function Bad({ items }) { items.push("new"); // ❌ NEVER mutate props! } // children prop — content between tags: function Card({ title, children }) { return ( <div className="card"> <h2>{title}</h2> <div className="card-body">{children}</div> </div> ); } // Usage: <Card title="User Profile"> <p>This is the card content.</p> <button>Edit</button> </Card> // TypeScript props: interface ButtonProps { label: string; onClick: () => void; variant?: "primary" | "secondary"; disabled?: boolean; } function Button({ label, onClick, variant = "primary", disabled }: ButtonProps) { return <button className={variant} onClick={onClick} disabled={disabled}>{label}</button>; } // Data flows DOWN (parent → child) // Events flow UP (child → parent via callbacks) // This is "one-way data flow" — predictable and debuggable
Data that changes over time. When state updates, React re-renders.
// useState — the most fundamental hook: import { useState } from "react"; function Counter() { const [count, setCount] = useState(0); // ↑ value ↑ updater ↑ initial value return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>+</button> <button onClick={() => setCount(count - 1)}>-</button> <button onClick={() => setCount(0)}>Reset</button> </div> ); } // State rules: // 1. Call hooks at the TOP of your component (not inside if/loops) // 2. State updates trigger a re-render // 3. State is preserved between renders // 4. Each component instance has its own state // Object state — always spread to create new reference: const [user, setUser] = useState({ name: "", email: "" }); // ❌ BAD — mutating existing object: user.name = "Alice"; setUser(user); // React won't re-render (same reference!) // ✓ GOOD — new object: setUser({ ...user, name: "Alice" }); // Array state: const [items, setItems] = useState([]); // Add: setItems([...items, newItem]); // Remove: setItems(items.filter(i => i.id !== targetId)); // Update one: setItems(items.map(i => i.id === targetId ? { ...i, done: true } : i)); // Functional updates (when new state depends on old): setCount(prev => prev + 1); // ✓ always gets latest value
How React decides what to update in the DOM.
// React rendering cycle: // 1. State changes (setState called) // 2. React calls your component function again // 3. Returns new JSX (virtual DOM) // 4. React DIFFS old vs new virtual DOM // 5. Only changed DOM nodes are updated (reconciliation) // Example: function App() { const [name, setName] = useState("World"); console.log("App rendered!"); // logs on every state change return ( <div> <h1>Hello, {name}!</h1> {/* updates text node only */} <input onChange={e => setName(e.target.value)} /> <ExpensiveList /> {/* re-renders too! */} </div> ); } // Hooks overview (the essential ones): // useState — state that triggers re-renders // useEffect — side effects (fetch data, subscriptions) // useRef — mutable value that doesn't trigger re-render // useMemo — cache expensive computations // useCallback — cache function references // useEffect — run code after render: import { useEffect } from "react"; function UserProfile({ userId }) { const [user, setUser] = useState(null); useEffect(() => { // Runs after component renders: fetch("/api/users/" + userId) .then(r => r.json()) .then(data => setUser(data)); // Cleanup (runs before next effect or unmount): return () => { /* cancel subscription, etc. */ }; }, [userId]); // ← dependency array: re-run when userId changes if (!user) return <p>Loading...</p>; return <h1>{user.name}</h1>; } // Dependency array rules: // [] — run once on mount only // [a, b] — run when a or b changes // (omitted) — run after every render (rarely want this)
Common questions about introduction to react.