DEV Community

Cover image for Mastering React.js: The Ultimate Practical Guide with Real-World Examples, Every Hook Explained, Routing & Redux
Abanoub Kerols
Abanoub Kerols

Posted on

Mastering React.js: The Ultimate Practical Guide with Real-World Examples, Every Hook Explained, Routing & Redux

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" />
Enter fullscreen mode Exit fullscreen mode

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>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

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)} />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>;
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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 })} 
      />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>;
}
Enter fullscreen mode Exit fullscreen mode

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>;
});
Enter fullscreen mode Exit fullscreen mode

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");
  // ...
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

Protected Route Example

function ProtectedRoute({ children }) {
  const isLoggedIn = useContext(AuthContext);
  return isLoggedIn ? children : <Navigate to="/login" />;
}

// Usage
<Route path="/dashboard" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} />
Enter fullscreen mode Exit fullscreen mode

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 }
});
Enter fullscreen mode Exit fullscreen mode
// 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;
Enter fullscreen mode Exit fullscreen mode

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>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Top comments (0)