SYP Start Your Path

Module 3: Frontend Frameworks & React

Why Frontend Frameworks Exist

Module 2 covered manipulating the DOM directly. At small scale that's fine — but as an app grows, manually finding elements and updating them in sync with changing data becomes error-prone and hard to maintain. Frameworks solve this by letting you describe what the UI should look like for a given piece of data, and handling the actual DOM updates for you.

Core ideas shared across almost every frontend framework:

React Basics: JSX, Components, Props & State

React is a JavaScript library (not a language, not a framework on its own) for building UIs out of components.

// JSX — HTML-like syntax written directly inside JavaScript
function Greeting({ name }) {      // props are received as a function argument
  return <h1>Hello, {name}!</h1>;
}

// Using it elsewhere
<Greeting name="Chiru" />
import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0); // state — starts at 0

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}
// Conditional rendering and lists — both just plain JavaScript inside JSX
function ItemList({ items, isLoading }) {
  if (isLoading) return <p>Loading...</p>;

  return (
    <ul>
      {items.map(item => <li key={item.id}>{item.name}</li>)}
    </ul>
  );
}

The key prop on list items helps React track which item is which across re-renders — always use a stable, unique value (like a database ID), never the array index if the list can reorder.

React Hooks

useState(initial)        // local component state
useEffect(() => { ... }, [deps])  // run code in response to renders (data fetching, subscriptions)
useRef(initial)            // a mutable value that persists without triggering re-renders
useMemo(() => calc(), [deps]) // cache an expensive calculation between renders
useCallback(fn, [deps])       // cache a function reference between renders
useContext(MyContext)           // read shared data from a Context Provider, without prop-drilling
useEffect(() => {
  fetch("/api/users")
    .then(res => res.json())
    .then(data => setUsers(data));
}, []); // empty array — runs once, after the first render

// Custom hooks — extract reusable logic out of a component, prefixed with "use"
function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);
  useEffect(() => {
    const handler = () => setWidth(window.innerWidth);
    window.addEventListener("resize", handler);
    return () => window.removeEventListener("resize", handler); // cleanup
  }, []);
  return width;
}

React Router, Next.js & the React Ecosystem

React Router adds client-side routing to a React SPA — different URLs render different components, without a full page reload:

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/users/:id" element={<UserProfile />} />
</Routes>

Next.js is not a different language or a competitor to React — it's a framework built ON TOP of React, adding file-based routing, server-side rendering, and API routes, with a more opinionated, batteries-included structure than plain React + React Router.

Component architecture at scale typically separates presentational components from ones that hold state/data logic, keeps API calls in dedicated functions/hooks, and handles loading/error states explicitly around every async operation — patterns worth learning deliberately as an app grows past a handful of components. Testing React components commonly uses Testing Library (Module 3's Tooling chapter) to test behavior from a user's perspective rather than implementation details.

Vue, Angular, Svelte & Others

All of these solve the same core problem (components + reactive state) with different syntax and tradeoffs — React remains the most widely used in the broader JavaScript job market, which is why this course covers it in the most depth.