Getting Started with React

There are two ways into React. You can drop three lines into an HTML file and have a working component in a minute, which suits trying an idea or adding one interactive widget to a page that is otherwise server-rendered. Or you can scaffold a project with a build tool, which is what every real application uses: JSX compiled ahead of time, hot module replacement while you edit, and a minified bundle at the end.This section walks both paths, then explains the files a scaffolded project gives you, the frameworks that sit a level above, and the two tools you will keep open all chapter.

2.1.1 What React Is and the Problem It Solves

React is an open-source (MIT) library for building user interfaces, created at Facebook and now developed by the React Foundation and a large community. It runs in the browser, on the server through Node.js, and — via React Native — on iOS and Android. It is not a framework: no router, no HTTP client, no opinion about folder layout.The problem it solves is the one Volume 1 leaves you with. Plain DOM code keeps the truth of your interface in the DOM itself, so every state change becomes a list of edits: find the counter, set its text, find the empty-cart message, hide it, enable the checkout button. Miss one edit and the screen disagrees with your data. React inverts that: you write a function returning what the screen should look like for the current data, and React works out the edits.Figure 2.1: Imperative DOM updates versus React's render-and-reconcile cycleA component is a function, and given the same props and state it must return the same markup — that is what makes the comparison safe to run whenever React likes. Its return value is neither DOM nor a string: it is a tree of plain objects describing elements, cheap to build and cheap to throw away. React keeps the previous tree, walks both, and produces the shortest list of DOM operations that turns one into the other: reconciliation. Under the hood: React has not diffed trees in a single blocking pass since React 16 replaced the stack reconciler with Fiber in 2017. A fiber is a unit of work with pointers to its parent, child and sibling, so rendering can pause between fibers, let the browser paint, and resume — the foundation of the concurrent features in Section 2.8. Two consequences follow. Because output depends only on inputs, a component is reusable and testable in isolation. And because React owns the DOM edits, it decides when to make them: batching several state updates into one commit, or deferring a low-priority update so typing stays smooth.

2.1.2 A Short History of React

React grew out of a Facebook prototype by Jordan Walke, first called F-Bolt and then FaxJS. It shipped to the News Feed in 2011 and to Instagram in 2012, and was open-sourced at JSConf US in Facebook's Seattle office on 29 May
  • The reception was hostile: to an audience trained on templates and separation of concerns, mixing markup

  • into JavaScript looked like a step backward. The argument was settled by use rather than debate. Date Release What it introduced 29 May 2013 Open-sourced Components, JSX, virtual DOM 26 Sep 2017 React 16 Fiber, portals, MIT license Feb 2019 React 16.8 Hooks in function components 29 Mar 2022 React 18 Concurrent rendering, batching 5 Dec 2024 React 19 Actions, use, refs as props 9 Sep 2026 React 19.3 View Transitions, fragment refs Table 2.1: Milestones in React's release history Two of those rows changed how React code looks. Hooks in 16.8 made the class component obsolete for new work: state, lifecycle and context all became function calls, and the render/componentDidMount/this.setState vocabulary faded. Fiber in 16 was invisible at the time but made React 18's concurrent rendering possible, and with it Suspense, transitions and streaming server rendering.The licensing history still comes up in interviews. From late 2014 React carried a three-clause BSD license plus a patent grant that terminated if you sued Facebook over patents. The Apache Software Foundation ruled that incompatible with its own projects, WordPress said it would look elsewhere, and on 22 September 2017 Facebook relicensed React, Jest, Flow and Immutable.js under plain MIT, shipping the change with React 16. Governance moved next: the React Foundation, announced on 7 October 2025 and launched on 24 February 2026, holds the trademark and stewardship of React and React Native under the Linux Foundation. Did you know? The virtual DOM was never the point, and the React team has said so repeatedly. The point is that rendering is a pure function of state; an in-memory tree is one way to make that affordable. Svelte and Solid reach the same programming model by compiling the tree away entirely.

    2.1.3 Adding React Directly to an HTML Page

    You can run React with no build step, which is the fastest way to try an idea or to add one interactive widget to a page your server already renders. Three things have to be in place: React and React DOM as modules, a DOM node to render into, and something that understands JSX.Older tutorials load react.development.js and react-dom.development.js as UMD scripts and use the globals React and ReactDOM. That recipe stops working at React 19, whose UMD builds were dropped: unpkg.com/react@19.3.0/umd/react.development.js returns 404. The replacement is an import map, which lets the browser resolve a bare specifier such as react to a URL, so the import statements of a real project also work in a single file.

    <!doctype html>

    <html lang="en">

    <head>

    <meta charset="utf-8">

    <script type="importmap">

    {"imports": {

    "react": "https://esm.sh/react@19.3.0",

    "react-dom/client": "https://esm.sh/react-dom@19.3.0/client"

    }}

    </script>

    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@8.0.5/babel.min.js"></script>

    <style>body { font: 16px system-ui, sans-serif; margin: 20px } button { font: inherit }</style>

    </head>

    <body>

    <div id="root"></div>

    <script type="text/babel" data-type="module">

    import React, { useState } from 'react';

    import { createRoot } from 'react-dom/client';

    function LikeButton() {

    const [likes, setLikes] = useState(0);

    return <p>

    <button onClick={() => setLikes(likes + 1)}>Like</button>

    {' '}{likes} {likes === 1 ? 'person likes' : 'people like'} this.

    </p>;

    }

    createRoot(document.getElementById('root')).render(<LikeButton />);

    </script>

    </body>

    </html>

    Listing 2.1: React 19 on a page with no build step Figure 2.2: Browser output of Listing 2.1Click the button and the sentence updates: setLikes schedules a re-render, LikeButton runs again with the new value, and React rewrites one text node. createRoot attaches React to a DOM container and is the only entry point in React 19 — ReactDOM.render was removed.Two details are easy to miss. type="text/babel" hands the script to Babel Standalone instead of the browser, and data-type="module" tells Babel the code contains import statements, so it re-injects the compiled result as a module. Babel Standalone compiles JSX with the classic runtime, turning <p> into React.createElement('p', ...), so React must be imported by name; drop that import and the page throws React is not defined. Build tools use the automatic runtime and need no such import (Section 2.2.1). Warning: Never ship this arrangement. Babel Standalone is 2.4 MB of minified compiler that recompiles your JSX in every visitor's browser on every load, and esm.sh sits in your critical path. For a page that must stay build-free, precompile once with npx babel src --out-dir js --presets @babel/preset-react and serve plain modules.

    2.1.4 Creating a Project with Vite

    For anything you intend to keep, start with a build tool. Vite is the lightest of the recommended options: it compiles JSX and TypeScript with Oxc, a transformer written in Rust, serves your source as native ES modules in development so startup does not depend on project size, and bundles for production with Rolldown.

    npm create vite@latest catalog -- --template react

    cd catalog

    npm install

    npm run dev

    Listing 2.2: Scaffolding and running a React project The -- passes the rest of the arguments to the scaffolder rather than to npm; use react-ts for a TypeScript project (Section 2.13), or leave the arguments off and create-vite asks which framework and variant you want. Installing pulls in a short dependency list — 24 packages on the run recorded here — and npm run dev starts the development server:

    VITE v8.3.0 ready in 277 ms

    ➜ Local: http://localhost:5177/

    ➜ Network: use --host to expose

    Output of Listing 2.2 Open that address and edit src/App.jsx. The change appears without a reload and without losing component state, because Vite's React plugin patches the updated module in place — hot module replacement. If state does get reset, you probably edited something outside a component. npm run build then produces the deployable version in dist/:

    vite v8.3.0 building client environment for production...

    ✓ 20 modules transformed.

    dist/index.html 0.45 kB │ gzip: 0.29 kB

    dist/assets/index-DykytF2W.css 4.10 kB │ gzip: 1.47 kB

    dist/assets/index-CyBHeG3D.js 222.52 kB │ gzip: 69.26 kB

    ✓ built in 302ms

    Output of Listing 2.2 React itself accounts for most of those 222 kB — about 69 kB over the wire after gzip. The hashed file names let you cache the assets forever and invalidate them by changing the hash, and npm run preview serves dist/ locally so you can check the production build before deploying it. Tip: npm create vite@latest always fetches the newest scaffolder, so your template may differ from the output above — the React template switched its linter from ESLint to oxlint, for example. Read the generated package.json rather than assuming what the scripts do.

    2.1.5 The Anatomy of a React Project

    A scaffolded project has fewer moving parts than it looks. Everything below src/ is yours; everything above it is configuration you will touch a few times a year.

    catalog/

    ├─ index.html the real entry point: loads /src/main.jsx as a module

    ├─ package.json dependencies and the dev / build / preview scripts

    ├─ vite.config.js Vite plugins; the React plugin enables JSX and HMR

    ├─ public/ copied to dist/ byte for byte, served as /favicon.svg

    └─ src/

    ├─ main.jsx creates the React root and renders <App />

    ├─ App.jsx the root component; index.css and App.css sit beside it

    └─ assets/ images imported from code, hashed at build time

    Listing 2.3: What create-vite generates for the React template index.html sitting in the project root surprises people who expect it under public/. Vite treats HTML as a source file: it parses the page, rewrites <script type="module" src="/src/main.jsx"> to point at the bundled output, and injects the stylesheet links. Files in public/ are the opposite — never processed, never hashed, always at the path you give them. Use public/ for robots.txt and favicons, src/assets/ for anything you import.

    import { StrictMode } from 'react'

    import { createRoot } from 'react-dom/client'

    import './index.css'

    import App from './App.jsx'

    createRoot(document.getElementById('root')).render(

    <StrictMode>

    <App />

    </StrictMode>,

    )

    Listing 2.4: src/main.jsx, the bridge between the page and React Those lines are the whole boundary between the DOM and React. createRoot claims the <div id="root"> from index.html, and render hands it a component tree. StrictMode renders nothing itself; in development it double-invokes components and effects to surface impure code and missing cleanup (Section 2.11.8), and it is stripped from production builds. Importing a CSS file from JavaScript is a bundler convention, not a React one. Tip: There is no mandated layout below src/. Small projects keep every component in src/components/; larger ones group by feature (src/cart/, src/catalog/) so that deleting a feature means deleting one directory. Pick one early — moving files later breaks every import path.

    2.1.6 Frameworks and Other Toolchains

    Vite gives you a bundler and nothing else. The moment an application needs routes, data loading or server rendering, you either assemble those yourself or start from a framework that already made the decisions. The React documentation now recommends the second path for most new applications. Starter Command What you get Reach for it when Vite npm create vite@latest Bundler and dev server The app is one page Next.js npx create-next-app@latest Routes, SSR, server components Content or commerce React Router npx create-react-router@latest Routes, loaders, actions, SSR Data-heavy dashboards Expo npx create-expo-app@latest Android, iOS and web One codebase, three targets Parcel npm install -D parcel Zero-config bundler You want no config file Rsbuild npm create rsbuild@latest Rspack-based bundler Migrating from webpack Table 2.2: Ways to start a React project, and the command that scaffolds each one Next.js and React Router in framework mode are the two you will meet most often in job postings, and they are closer than their marketing suggests: both render on the server and both colocate data loading with routes. Chapter 5 covers Next.js; Sections 2.16 and 2.17 cover React Router, including the framework mode.One name is missing on purpose. Create React App, for a decade the default answer to "how do I start a React project", was sunset on 14 February 2025; it is unmaintained and never gained routing or data fetching. If you inherit a CRA project, plan a migration to Vite: the source usually moves unchanged, and the work is in index.html, environment variable prefixes (REACT_APP_ becomes VITE_) and the Jest-to-Vitest switch of Section 2.15. Note: Gatsby, Neutrino and Razzle appear in older tutorials as blessed toolchains; none is listed in the current documentation, which flags TanStack Start and RedwoodSDK as the up-and-coming pair instead. Nx remains reasonable for a monorepo holding a React app beside Node services — exactly the shape of a MERN project.

    2.1.7 Online Editors and Sandboxes

    Nothing in this chapter needs a local install to try. A browser sandbox gives you a React project in seconds and — more usefully — a URL. When you report a bug or share a snippet with a colleague, a link to a running reproduction saves everyone the "it works here" round trip; maintainers of React libraries routinely close issues that arrive without one. Sandbox Where the code runs Best for StackBlitz In your browser, on WebContainers Full projects, instant boot CodeSandbox A container in the cloud Repos, branches, npm scripts CodePen In your browser, no Node Single-file snippets and demos Replit A container in the cloud Pairing and teaching Table 2.3: Browser sandboxes for React work The interesting one technically is StackBlitz. Its WebContainers (https://webcontainers.io/) runtime brings Node.js into the browser tab itself, so npm install and vite dev run on your own machine with no server involved: boot is instant and nothing you paste leaves the browser. CodeSandbox takes the opposite approach and gives you a real Linux container, slower to start but able to run anything Node runs, including an Express server from Chapter 3.The React documentation links straight to a React project on StackBlitz (https://stackblitz.com/fork/react) and a new CodeSandbox (https://codesandbox.io/s/new); add ?file=src/App.jsx to a shared link to open it on a particular file. For a quick snippet a sandbox beats the import-map page of Section 2.1.3.

    2.1.8 React Developer Tools

    The Elements panel shows the DOM React produced, which is the wrong level of detail: it cannot say which component rendered a node, what props it received or what its state is. React Developer Tools, the official extension, adds two tabs — Components and Profiler — that work at the level you write in. Install it from the Chrome Web Store, Firefox Add-ons or the Edge add-ons site; for React Native and other non-browser targets, npx react-devtools opens the same interface as a standalone app.Figure 2.3: The Components tab of React Developer Tools (image: react.dev, CC BY 4.0)Select a node in the component tree and the right-hand pane lists its props, state and hooks in order, all editable: change a prop and the component re-renders immediately, the fastest way to check an empty state or an error branch without touching code. The eye icon reveals the matching DOM node in the Elements panel, <> jumps to the source, and the bug icon logs props and state to the console.The Profiler tab records a session and reports, per commit, which components re-rendered and how long they took. Section 2.12.1 uses it properly; for now, turn on Highlight updates when components render in the settings gear and click around. Boxes flashing around parts of the screen that did not change mean some state lives too high in the tree. Note: A production build hides component names behind minified identifiers, and the Components tab says so. Development builds keep the names — one reason to debug against npm run dev rather than npm run preview.