โ† Back | React + TypeScript Basics
Week 7
Week 7 ยท AI & Frontend

React + TypeScript Basics

React is the most popular frontend library in the world. Combined with TypeScript, you get type-safe, maintainable UI code. This week we build the frontend that talks to your Spring Boot API.

โš›๏ธ React 18 ๐Ÿ”ท TypeScript ๐ŸŽฃ Hooks
๐Ÿง 
Concept
What is React?
Traditional HTML+JS: You write HTML, then write JavaScript that manually manipulates the DOM (document.getElementById, innerHTML = ...). When data changes, you update the DOM yourself โ€” error-prone and messy.

React: You write components that describe what the UI should look like for a given state. When state changes, React automatically figures out the minimal DOM changes needed. You think about state, not DOM manipulation.
Old Way (Vanilla JS)React Way
Manually update DOMDeclare what UI looks like, React handles DOM
State scattered in variablesState managed declaratively with useState
Reuse via copy-pasteReusable components
Hard to testComponents are testable functions
๐Ÿš€
Step 1
Create a React + TypeScript Project
# Vite โ€” fastest modern React project setup npm create vite@latest student-ui -- --template react-ts cd student-ui npm install npm run dev # starts dev server at http://localhost:5173

Key files in the project

student-ui/ โ”œโ”€โ”€ src/ โ”‚ โ”œโ”€โ”€ App.tsx โ† Root component โ”‚ โ”œโ”€โ”€ main.tsx โ† Entry point (renders App to #root div) โ”‚ โ”œโ”€โ”€ components/ โ† Your reusable components โ”‚ โ”œโ”€โ”€ pages/ โ† Page-level components โ”‚ โ””โ”€โ”€ types/ โ† TypeScript type definitions โ”œโ”€โ”€ index.html โ”œโ”€โ”€ tsconfig.json โ† TypeScript configuration โ””โ”€โ”€ package.json
๐Ÿงฉ
Core Concept
Components and JSX
A React component is like a custom HTML tag you define yourself. Instead of <button>, you create <PayButton label="Pay Now" />. Components are reusable, composable, and self-contained.
StudentCard.tsx โ€” A simple component
// JSX = JavaScript + HTML-like syntax // A component is just a function that returns JSX function StudentCard() { // JavaScript logic goes here const name = "Rahul Sharma"; const isActive = true; // JSX is returned โ€” looks like HTML but it's JavaScript return ( <div className="card"> <h2>{name}</h2> {/* {} = JS expression in JSX */} <p>City: Pune</p> {isActive && <span className="badge">Active</span>} </div> ); } export default StudentCard;
JSX Rules: Use className instead of class (class is a reserved word in JS). Every component must return a single root element (or use <></> fragment). Components start with a Capital letter.
๐Ÿ“จ
Core Concept
Props โ€” Passing Data to Components
Props are like function arguments for components. The parent passes data, the child receives and displays it. Data flows one way: parent โ†’ child.
// Define the shape of props with TypeScript interface interface StudentCardProps { name: string; email: string; city: string; isActive?: boolean; // ? = optional prop } // Component receives props as argument function StudentCard({ name, email, city, isActive = true }: StudentCardProps) { return ( <div className="card"> <h2>{name}</h2> <p>๐Ÿ“ง {email}</p> <p>๐Ÿ“ {city}</p> {isActive && <span>โœ… Active</span>} </div> ); } // Parent uses the component function App() { return ( <div> <StudentCard name="Rahul" email="rahul@email.com" city="Pune" /> <StudentCard name="Priya" email="priya@email.com" city="Mumbai" isActive={false} /> </div> ); }
โšก
Core Hook
useState โ€” Component State
State is memory inside a component. When state changes, React re-renders the component. Think of it like a scoreboard in a cricket match โ€” when the score changes, the board updates.
import { useState } from 'react'; function Counter() { // useState(initialValue) returns [currentValue, setterFunction] const [count, setCount] = useState<number>(0); const [name, setName] = useState<string>(""); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> <button onClick={() => setCount(0)}>Reset</button> <input value={name} onChange={(e) => setName(e.target.value)} // controlled input placeholder="Enter name" /> <p>Hello, {name || "stranger"}!</p> </div> ); }
NEVER mutate state directly. Don't do count = count + 1. Always use the setter function: setCount(count + 1). Direct mutation won't trigger a re-render.
๐Ÿ”„
Core Hook
useEffect โ€” Side Effects
useEffect runs code after the component renders. Use it for: fetching data from an API, setting up subscriptions, updating the page title, starting timers.
import { useState, useEffect } from 'react'; function StudentList() { const [students, setStudents] = useState<Student[]>([]); const [loading, setLoading] = useState(true); // useEffect(effect, dependencies) // Empty [] = run once after first render (like componentDidMount) useEffect(() => { async function fetchStudents() { try { const response = await fetch('http://localhost:8080/api/students'); const data = await response.json(); setStudents(data); } finally { setLoading(false); } } fetchStudents(); }, []); // [] = only run on mount if (loading) return <p>Loading...</p>; return ( <ul> {students.map(student => ( <li key={student.id}>{student.name}</li> ))} </ul> ); }
๐Ÿ”—
Integration
Calling Your Spring Boot API
Complete example with TypeScript types
types/Student.ts
export interface Student { id: number; name: string; email: string; city: string; }
StudentList.tsx โ€” Full CRUD component
import { useState, useEffect } from 'react'; import type { Student } from '../types/Student'; const API_URL = 'http://localhost:8080/api/students'; export function StudentList() { const [students, setStudents] = useState<Student[]>([]); const [newName, setNewName] = useState(''); const [newEmail, setNewEmail] = useState(''); useEffect(() => { loadStudents(); }, []); async function loadStudents() { const res = await fetch(API_URL); setStudents(await res.json()); } async function addStudent() { await fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: newName, email: newEmail }) }); setNewName(''); setNewEmail(''); loadStudents(); // refresh list } async function deleteStudent(id: number) { await fetch(`${API_URL}/${id}`, { method: 'DELETE' }); loadStudents(); } return ( <div> <h1>Students</h1> <div> <input value={newName} onChange={e => setNewName(e.target.value)} placeholder="Name" /> <input value={newEmail} onChange={e => setNewEmail(e.target.value)} placeholder="Email" /> <button onClick={addStudent}>Add</button> </div> {students.map(s => ( <div key={s.id}> <strong>{s.name}</strong> โ€” {s.email} <button onClick={() => deleteStudent(s.id)}>Delete</button> </div> ))} </div> ); }
CORS error? When React (port 5173) calls Spring Boot (port 8080), the browser blocks it. Fix: Add @CrossOrigin(origins = "http://localhost:5173") to your Spring controller, or configure CORS globally in WebMvcConfigurer.
๐ŸŽฏ
Interview Prep
Common Interview Questions
QWhat is React and why use it?

React is a JavaScript library for building user interfaces using reusable components. Instead of manually manipulating the DOM, you declare what the UI should look like for a given state, and React handles updates efficiently via its Virtual DOM.

Benefits: reusable components, predictable state management, huge ecosystem, excellent performance via virtual DOM diffing, strong TypeScript support.

QWhat is the difference between state and props?

Props (properties) are passed FROM parent TO child โ€” they're read-only. A child component cannot modify its own props.

State is managed WITHIN a component using useState. It's the component's own memory. When state changes, the component re-renders.

Rule: if data is needed by multiple components, lift state up to their common parent and pass it down as props.

QWhat is useEffect and when do you use it?

useEffect runs side effects after rendering. "Side effects" are operations outside the normal render cycle: API calls, subscriptions, DOM manipulation, timers.

The second argument (dependencies array) controls when it runs:

  • useEffect(() => {...}, []) โ€” runs once after first render (on mount)
  • useEffect(() => {...}, [userId]) โ€” runs when userId changes
  • useEffect(() => {...}) โ€” runs after EVERY render (rarely needed)
QWhy use TypeScript with React?

TypeScript adds static typing to JavaScript. With React + TypeScript:

  • Define the shape of props with interfaces โ€” get compile-time errors if you pass wrong types
  • API response types are explicit โ€” no guessing what fields exist
  • Better IDE autocomplete and refactoring support
  • Errors caught at compile time, not at runtime in production
QWhat is CORS and how do you fix it?

CORS (Cross-Origin Resource Sharing) is a browser security mechanism that blocks frontend code from calling a different origin (different protocol, domain, or port).

React (localhost:5173) calling Spring Boot (localhost:8080) = different ports = CORS error.

Fix in Spring Boot: Add @CrossOrigin annotation on controllers, or configure globally with a CORS configuration bean that allows your frontend's origin.