React in Focus
Expert · 18 min read · ▶ live playground · ✦ checkpoint
React feels strange for about ten minutes, then you recognize the old loop wearing a sharper suit. React is a JavaScript UI library, a package focused on describing interfaces from state, and its main promise is direct: write components that say what the screen should look like, then let React keep the DOM matched.
You are not learning magic now. You are putting names on moves you already know: state, render, events, derived values, and small pieces that cooperate.
Components and JSX
A component is a JavaScript function that returns a description of UI. In React, that description is usually written with JSX, HTML-shaped syntax that lets markup and JavaScript values sit in one expression.
function TaskSummary({ openCount }) {
return (
<section>
<h2>Tasks</h2>
<p>{openCount} open</p>
</section>
);
}Read the braces as "drop back into JavaScript here." The <section> shape is not a string of HTML. It is a UI description that React can read. The build tool turns JSX into normal JavaScript before the browser runs it, just like Vite already turned human-shaped source into browser-shaped output in Part V.
React then reconciles the UI, which means it compares the latest description with the previous one and updates the real DOM where needed. You describe the desired table setting; React figures out which plates moved.
Props and composition
Props are values passed into a component by its parent. They are like function arguments for UI pieces: the parent chooses the facts, the child describes how those facts look.
function TaskRow({ task, onMarkDone }) {
return (
<li>
<span>{task.done ? "Done" : "Open"}</span>
<span>{task.title}</span>
<button type="button" onClick={() => onMarkDone(task.id)}>
Mark done
</button>
</li>
);
}That component is reusable because it does not own the whole app. It receives one task plus a callback for marking that task done, then renders one row.
Composition means building bigger UI by nesting smaller components, like assembling a dashboard from cards instead of carving the whole page from one block.
function TaskSummary({ openCount }) {
return <p>{openCount} open</p>;
}
function TaskList({ tasks, onMarkDone }) {
const openCount = tasks.filter((task) => !task.done).length;
return (
<section>
<TaskSummary openCount={openCount} />
<ul>
{tasks.map((task) => (
<TaskRow key={task.id} task={task} onMarkDone={onMarkDone} />
))}
</ul>
</section>
);
}A key is React's stable identity hint for a list item. When tasks move, appear, or disappear, key={task.id} helps React match "this row before" to "this row now."
Notice the old pattern: derive openCount from tasks, then render from the facts. React did not invent that discipline. It rewards it.
State means render again
State is a component's remembered UI facts. In React, useState is a hook, a function React gives components so they can connect to React features.
import { useState } from "react";
function TaskBoard() {
const [tasks, setTasks] = useState([
{ id: 1, title: "Draft release note", done: false },
{ id: 2, title: "Pay invoice", done: true },
]);
function markDone(id) {
setTasks((currentTasks) =>
currentTasks.map((task) => {
if (task.id !== id) {
return task;
}
return { ...task, done: true };
}),
);
}
return (
<TaskList tasks={tasks} onMarkDone={markDone} />
);
}The pair [tasks, setTasks] is the deal: tasks is the current value for this render, and setTasks schedules a new render with a new value. The updater form, setTasks((currentTasks) => ...), receives the current state so your update does not depend on an old closure.
This is the phrase that unlocks React: thinking in renders means treating each render as a snapshot. During one render, props and state are fixed. An event can request the next state, but the current render does not mutate in place. React calls your component again, gets a new UI description, and reconciles the DOM.
That is why immutable updates matter. If you push into the old tasks array, you are scribbling on yesterday's scorecard. If you return a new array with the changed task, React gets a clean new fact to render from.
Effects touch the outside world
Rendering should mostly be a calculation: props and state in, UI description out. A side effect is work that reaches outside that calculation, such as changing document.title, starting a timer, subscribing to events, or talking to a server.
useEffect is React's hook for synchronizing with those outside systems after React has rendered.
import { useEffect } from "react";
function PageTitle({ openCount }) {
useEffect(() => {
document.title = `${openCount} open tasks`;
}, [openCount]);
return null;
}The second argument is the dependency array, the list of values the effect depends on. Here, React reruns the effect when openCount changes. If an effect sets up something long-lived, like a timer or subscription, it can return a cleanup function, a function that undoes the setup before React reruns or removes the component.
Do not read useEffect as "the place for all code that feels active." It is the door to outside systems. Sorting a list, deriving a count, choosing visible tasks, and formatting labels usually belong in render. Subscribing to a browser API belongs in an effect.
The compiler era
React has always cared about rendering only what needs work, but older React code often grew manual performance wrappers. Memoization is remembering a previous calculation or rendered result when inputs have not changed. It can help, but too much manual memoization turns clear code into padded code.
The current React era changes that pressure. React Compiler is a build-time tool that analyzes components before the browser runs them. React 19.2 sits in the React Compiler 1.0 era; the compiler reached 1.0 in October 2025 and can automatically memoize many component calculations when the code follows React's rules. That means less hand-written caching code in many apps.
The careful wording matters: the compiler does not make unclear components fast by magic. It cannot fix a bad state shape, a render function with surprise side effects, or network work started in the wrong place. It works best when your components are boring in the good way: props and state in, UI description out.
The ecosystem around React
React itself is the view layer, the part of an app responsible for what the user sees. A real app also needs surrounding tools.
A router maps URLs to views, so /tasks/open can show a different screen than /settings. A data layer manages server data: loading states, caching, retries, invalidation, and keeping remote facts separate from local UI facts. React DevTools is a browser inspection tool that shows the component tree, props, state, and render behavior.
Then there are frameworks built around React. Next.js is a React meta-framework, a framework around a framework that bundles routing, server rendering, which means rendering UI on a server before the browser receives it, data conventions, and deployment paths. React Server Components are React components that render on the server instead of shipping all their code to the browser, and they are mainstream through Next.js 16. The full rendering menu belongs in 25.4. For now, keep the boundary clean: React teaches the component mental model; the ecosystem decides how the whole app is routed, loaded, tested, inspected, and shipped.
React is popular because its core idea is small enough to learn and strong enough to scale: components receive facts, state changes ask for new renders, effects synchronize with the outside world, and tools gather around that model. Next, you widen the lens and compare React's answer with Vue, Svelte, Solid, Angular, and the signals idea those tools keep circling.
Checkpoint
Answer all three to mark this lesson complete