// Declarative: React handles the DOM
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
// Usage
<Greeting name="Alice" />
// React reconciles DOM changes
// automatically — no querySelector,
// no innerHTML manipulation needed
// JSX syntax
const element = (
<div className="card">
<h2>{user.name}</h2>
<p>Score: {user.score * 2}</p>
{user.isAdmin && <Badge />}
</div>
);
// What Babel compiles it to:
const element = React.createElement(
"div",
{ className: "card" },
React.createElement("h2", null, user.name)
);
// Function component (recommended)
function UserCard({ name, role }) {
return (
<div className="card">
<Avatar name={name} />
<h3>{name}</h3>
<span>{role}</span>
</div>
);
}
// Composition
function App() {
return (
<main>
<UserCard name="Alice" role="Admin" />
<UserCard name="Bob" role="Editor" />
</main>
);
}
function Button({ label, onClick, variant = "primary" }) {
return (
<button
className={`btn btn--${variant}`}
onClick={onClick}
>
{label}
</button>
);
}
// Parent passes props
<Button
label="Save"
variant="secondary"
onClick={() => handleSave()}
/>
// Children prop
<Panel>
<p>Any JSX can be a child.</p>
</Panel>
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
function increment() {
setCount(prev => prev + 1); // functional update
}
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+1</button>
<button onClick={() => setCount(0)}>
Reset
</button>
</div>
);
}
my-app/
├── index.html Entry HTML — mounts the React root
├── vite.config.js Build tool configuration
├── package.json Dependencies and scripts
└── src/
├── main.jsx Bootstrap — ReactDOM.createRoot()
├── App.jsx Root component
├── components/ Reusable, dumb UI components
├── pages/ Route-level components
├── hooks/ Custom React hooks
├── context/ React Context providers
└── assets/ Images, fonts, static files
// Terminal
npm create vite@latest my-app -- --template react
cd my-app && npm install && npm run dev
// src/main.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
ReactDOM.createRoot(
document.getElementById("root")
).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
import { useState, useEffect } from "react";
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
let cancelled = false;
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(data => {
if (!cancelled) setUser(data);
});
return () => { cancelled = true; }; // cleanup
}, [userId]); // re-run when userId changes
if (!user) return <p>Loading…</p>;
return <h1>{user.name}</h1>;
}
// ThemeContext.jsx
import { createContext, useContext, useState } from "react";
const ThemeContext = createContext("light");
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
// Consuming component (anywhere in tree)
function Header() {
const { theme, setTheme } = useContext(ThemeContext);
return <button onClick={() => setTheme(
theme === "light" ? "dark" : "light"
)}>Toggle</button>;
}
// hooks/useFetch.js
import { useState, useEffect } from "react";
export function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch(url)
.then(r => r.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [url]);
return { data, loading, error };
}
// Usage in a component
const { data, loading } = useFetch("/api/posts");
function TemperatureApp() {
const [celsius, setCelsius] = useState(0);
const fahrenheit = celsius * 9/5 + 32;
return (
<div>
<CelsiusInput
value={celsius}
onChange={setCelsius}
/>
<FahrenheitDisplay value={fahrenheit} />
</div>
);
}
// Child — controlled by parent
function CelsiusInput({ value, onChange }) {
return (
<input
type="number"
value={value}
onChange={e => onChange(Number(e.target.value))}
/>
);
}
// Controlled input
function ControlledForm() {
const [email, setEmail] = useState("");
function handleSubmit(e) {
e.preventDefault();
console.log(email);
}
return (
<form onSubmit={handleSubmit}>
<input
value={email}
onChange={e => setEmail(e.target.value)}
type="email"
/>
<button type="submit">Send</button>
</form>
);
}
// Uncontrolled — use sparingly
function UncontrolledForm() {
const inputRef = useRef(null);
return <input ref={inputRef} />;
}
React Router v6
Key Concepts
Solutions
Guidance