React turned 10 in 2023 and is more dominant than ever heading into 2026 — it powers the frontends of Meta, Airbnb, Netflix, and the majority of job listings asking for JavaScript UI skills. But the React you learn from a 2019 tutorial is meaningfully different from what you should be writing today. Class components are gone, Create React App is retired, and React Server Components have changed the default deployment model. This guide starts you on the right path.
What changed in 2026
- React 19 is stable. Actions, the new
use() hook for async data, and form handling improvements shipped. The mental model around async is simpler.
- React Server Components (RSC) are mainstream. Next.js App Router is the default for new projects; RSC lets you fetch data directly in a component without a separate API route.
- Vite replaced Create React App. If you're building a pure SPA or learning React without a meta-framework, use
npm create vite@latest.
- TypeScript is the default. Almost every template and tutorial now scaffolds TypeScript. JavaScript is still valid, but TS is what you'll find on the job.
The core mental model
React is a function: (props) => UI. A component is just a function that returns JSX (HTML-like syntax that React converts to DOM nodes).
// A simple component
function Greeting({ name }: { name: string }) {
return <h1>Hello, {name}!</h1>;
}
// Using it
<Greeting name="Alice" />
The entire UI is a tree of these functions. When data changes, React re-runs the relevant functions and updates only the changed parts of the DOM.
State with useState
State is data that, when it changes, causes the component to re-render.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
Rules: never mutate state directly (count++ breaks things). Always use the setter (setCount). State is local to the component instance.
Side effects with useEffect
useEffect runs code after a render — fetching data, subscribing to events, updating the document title.
import { useState, useEffect } from 'react';
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(setUser);
}, [userId]); // re-run when userId changes
if (!user) return <p>Loading…</p>;
return <p>{user.name}</p>;
}
The dependency array ([userId]) controls when the effect re-runs. Empty array ([]) = run once on mount. No array = run after every render (almost never what you want).
React in 2026: plain SPA vs Next.js
| Use case |
Best choice |
| Learning React |
Vite + React (npm create vite@latest) |
| Internal dashboard, SPA |
Vite + React + React Query |
| Public website with SEO |
Next.js App Router |
| E-commerce, content site |
Next.js App Router |
| Full-stack app with auth |
Next.js + Prisma / Drizzle |
For most production apps, Next.js App Router is the answer. It handles routing, server rendering, and data fetching in one framework.
The hooks you actually need first
| Hook |
What it does |
useState |
Local reactive state |
useEffect |
Run side effects after render |
useCallback |
Memoize a function reference |
useMemo |
Memoize an expensive computed value |
useContext |
Consume a React context |
useRef |
Hold a mutable value or DOM reference |
Learn them in that order. useCallback and useMemo only matter for performance; don't reach for them until you have a measured problem.
How to start
- Run
npm create vite@latest my-app -- --template react-ts and open the project.
- Build a to-do list with
useState and a list render.
- Add a
useEffect that fetches from a free API (JSONPlaceholder is fine).
- Break the UI into smaller components; pass data as props.
- Once that clicks, scaffold a Next.js project:
npx create-next-app@latest.
Common mistakes
Mutating state directly. state.items.push(x) doesn't trigger a re-render. Always spread: setItems([...items, x]).
Missing dependency arrays in useEffect. Omitting a dependency causes stale closures; ESLint's exhaustive-deps rule catches this automatically — enable it.
Putting everything in one component. The power of React is composition. If a component exceeds ~80 lines, look for a logical split.
Using Redux for simple apps. Zustand (tiny), React Query (server state), and Context (simple globals) cover 90% of real-world state needs without Redux boilerplate.
Learning class components first. They are legacy. Every new pattern, hook, and feature is function-component only.
What to skip
- Create React App — deprecated; use Vite.
- Redux from scratch for a new project — reach for Zustand or Jotai first.
- jQuery + React — they conflict; pick one model for DOM manipulation.
- React class components — you may encounter them in old codebases, but don't learn them as your foundation.
FAQ
Is React hard to learn?
The fundamentals (components, props, useState) take a weekend. The ecosystem and patterns (RSC, caching, data fetching) take months to feel fluent. Start narrow.
Should I learn React or Vue or Svelte in 2026?
React has the most jobs, the largest ecosystem, and the most learning resources. Svelte has the nicest DX. Vue sits in between. If employment is the goal, React first.
Do I need TypeScript for React?
Not to start, but yes for any real project. TS catches the props/state type errors that are the most common React bugs.
What is JSX?
JSX is a syntax extension that looks like HTML inside JavaScript. Babel/esbuild compiles it to React.createElement() calls. You write <div> and it becomes a function call.
Where to go next