React.js remains the king of front-end development in 2026. Built by Meta in 2013 and open-sourced in 2015, it powers Facebook, Instagram, Netflix, Airbnb, WhatsApp Web, and millions of production apps.
Unlike full frameworks, React is a library focused only on the UI layer β giving you total freedom. Its secret weapons? Virtual DOM, component architecture, and Hooks.
Letβs rewrite everything with way more practical examples, deep dive into every major Hook, full React Router routing, and Redux Toolkit (the modern standard).
1. JSX & Components β The Foundation
function Greeting({ name }) {
return <h1>Hello, {name}! π Today is {new Date().toLocaleDateString()}</h1>;
}
// Usage
<Greeting name="Abanoub" />
2. Props vs State β Real Example
Props = data passed down (read-only)
State = data that changes inside the component
// Parent
function App() {
const [userName, setUserName] = useState("Abanoub");
return <Profile name={userName} setName={setUserName} />;
}
// Child
function Profile({ name, setName }) {
return (
<>
<h2>{name}</h2>
<button onClick={() => setName("Ahmed")}>Change Name</button>
</>
);
}
3. Every React Hook Explained with Practical Examples
useState β Local State Management
Most used hook.
function Counter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
return (
<>
<h2>Count: {count}</h2>
<button onClick={() => setCount(c => c + step)}>+</button>
<button onClick={() => setCount(c => c - step)}>-</button>
<input type="number" value={step} onChange={e => setStep(+e.target.value)} />
</>
);
}
useEffect β Side Effects (API calls, timers, subscriptions)
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
.then(res => res.json())
.then(data => {
setUser(data);
setLoading(false);
});
}, [userId]); // β runs again only when userId changes
useEffect(() => {
document.title = user ? user.name : "Loading...";
}, [user]);
return loading ? <p>Loading...</p> : <h1>{user.name}</h1>;
}
useContext β Global Data Without Prop Drilling
// ThemeContext.js
const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
// Any component
function Button() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
Switch to {theme === "light" ? "Dark" : "Light"}
</button>
);
}
useReducer β Complex State Logic (like Redux but local)
Perfect for forms, shopping carts, game logic.
const initialState = { count: 0, step: 1 };
function reducer(state, action) {
switch (action.type) {
case "increment": return { ...state, count: state.count + state.step };
case "decrement": return { ...state, count: state.count - state.step };
case "setStep": return { ...state, step: action.payload };
default: return state;
}
}
function AdvancedCounter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
<h2>Count: {state.count}</h2>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
<input
value={state.step}
onChange={e => dispatch({ type: "setStep", payload: +e.target.value })}
/>
</>
);
}
useRef β Access DOM elements or persist values without re-render
function Timer() {
const intervalRef = useRef(null);
const [seconds, setSeconds] = useState(0);
useEffect(() => {
intervalRef.current = setInterval(() => setSeconds(s => s + 1), 1000);
return () => clearInterval(intervalRef.current);
}, []);
return <h2>Seconds: {seconds}</h2>;
}
// Another use: focus input
function FocusInput() {
const inputRef = useRef(null);
return (
<>
<input ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>Focus</button>
</>
);
}
useMemo β Cache expensive calculations
function ExpensiveList({ items, filter }) {
const filteredItems = useMemo(() => {
console.log("Filtering..."); // this runs only when filter changes
return items.filter(item => item.includes(filter));
}, [items, filter]);
return <ul>{filteredItems.map(item => <li key={item}>{item}</li>)}</ul>;
}
useCallback β Memoize functions (prevents child re-renders)
function Parent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
setCount(c => c + 1);
}, []); // empty deps = never recreated
return <Child onClick={handleClick} />;
}
const Child = React.memo(function Child({ onClick }) {
console.log("Child rendered");
return <button onClick={onClick}>Click me</button>;
});
Custom Hooks β Reuse Logic
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url).then(res => res.json()).then(setData).finally(() => setLoading(false));
}, [url]);
return { data, loading };
}
// Usage anywhere
function Dashboard() {
const { data: posts, loading } = useFetch("https://jsonplaceholder.typicode.com/posts");
// ...
}
4. Routing with React Router v6+ (Practical Multi-Page App)
npm install react-router-dom
// main.jsx
import { BrowserRouter, Routes, Route, Link, Navigate } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link> |
<Link to="/about">About</Link> |
<Link to="/users/1">User 1</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/users/:id" element={<UserProfile />} />
<Route path="*" element={<Navigate to="/" />} />
</Routes>
</BrowserRouter>
);
}
Protected Route Example
function ProtectedRoute({ children }) {
const isLoggedIn = useContext(AuthContext);
return isLoggedIn ? children : <Navigate to="/login" />;
}
// Usage
<Route path="/dashboard" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} />
5. Redux Toolkit β The Modern State Management Solution
Forget old Redux boilerplate. Redux Toolkit is the official way.
npm install @reduxjs/toolkit react-redux
// store.js
import { configureStore } from '@reduxjs/toolkit';
import cartReducer from './cartSlice';
export const store = configureStore({
reducer: { cart: cartReducer }
});
// cartSlice.js
import { createSlice } from '@reduxjs/toolkit';
const cartSlice = createSlice({
name: 'cart',
initialState: { items: [] },
reducers: {
addToCart: (state, action) => {
state.items.push(action.payload);
},
removeFromCart: (state, action) => {
state.items = state.items.filter(item => item.id !== action.payload);
}
}
});
export const { addToCart, removeFromCart } = cartSlice.actions;
export default cartSlice.reducer;
Using in Component
import { useSelector, useDispatch } from 'react-redux';
import { addToCart } from './cartSlice';
function Product({ product }) {
const dispatch = useDispatch();
const cartCount = useSelector(state => state.cart.items.length);
return (
<>
<button onClick={() => dispatch(addToCart(product))}>
Add to Cart ({cartCount})
</button>
</>
);
}
6. Bonus: Full Mini E-commerce App Structure (React + Router + Redux + Hooks)
- App.jsx β BrowserRouter + Routes
- CartPage.jsx β uses Redux + useSelector
- ProductPage.jsx β useState for quantity + useEffect for API
- ThemeProvider wrapping everything with useContext
Final Tips from a Senior Developer
- Always use useCallback + React.memo for performance.
- Prefer Redux Toolkit or Zustand for global state (Context + useReducer for simple cases).
- Use React Router v6.22+ with createBrowserRouter for data loaders in big apps.
- Learn TypeScript + React β it will save you weeks of bugs.
npm create vite@latest my-react-app -- --template react
cd my-react-app
npm install react-router-dom @reduxjs/toolkit react-redux
npm run dev
Top comments (0)