Building Interactive UIs with Modern React
2025-10-15
By the end of this session, you will be able to:
useState, useEffect)Prerequisites
✅ Solid understanding of JavaScript ES6+ (functions, objects, arrays, arrow functions, destructuring)
✅ Familiarity with HTML/CSS and basic DOM concepts
✅ Basic command-line and npm usage
✅ Completion of Session 2: JavaScript for React
💡 If you need a refresher: Review Session 2 materials on JavaScript fundamentals before continuing.
What We’re Building
Using: fullstack-minimal-app as our foundation
Goal: Build a complete React frontend ready for backend integration! 🎉
Philosophy: Learn by building, AI-assisted development, practical focus
Remember vanilla JavaScript from Session 2?
// Manual DOM manipulation (tedious!)
const button = document.querySelector('#loadBtn');
const output = document.querySelector('#output');
button.addEventListener('click', async () => {
output.innerHTML = 'Loading...';
const response = await fetch('/api/data');
const data = await response.json();
// Manual HTML creation (error-prone!)
output.innerHTML = '';
data.forEach(item => {
const div = document.createElement('div');
div.textContent = item.name;
output.appendChild(div);
});
});React Makes It Elegant:
function DataDisplay() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const loadData = async () => {
setLoading(true);
const response = await fetch('/api/data');
const result = await response.json();
setData(result);
setLoading(false);
};
return (
<div>
<button onClick={loadData}>Load Data</button>
{loading ? <p>Loading...</p> : null}
{data.map(item => <div key={item.id}>{item.name}</div>)}
</div>
);
}React = Declarative: “Here’s what the UI should look like” not “Here’s how to build it”
Scenario: You’re building a dashboard for a fast-growing startup. The product team adds 5 new features every sprint. How do you keep your UI code maintainable as complexity grows?
Answer: Component-based architecture! Each feature becomes a reusable, testable component that can evolve independently. This is why companies like Facebook created React—to manage massive, evolving UIs.
Key Principles:
What React Solves
Industry Usage
React’s component model has become the industry standard for building modern web applications. Understanding React prepares you for:
Learning React is not just about one library—it’s about understanding the component-based architecture pattern that dominates modern web development.
What You Need to Run React Locally
Essential Tools:
Quick Start (if starting from scratch):
# Install Node.js from nodejs.org if not already installed
# Create new React project with Vite (Run this command in terminal)
npm create vite@latest my-react-app -- --template react
# Navigate and install
cd my-react-app # Navigate into the project directory
npm install
# Start development server
npm run devFor this course: We provide a ready-made fullstack app, so you can focus on learning React rather than configuration! ⚡
📦 Why We Use a Starter Template
Pedagogical Approach: Rather than spending time on tooling configuration, we provide fullstack-minimal-app that includes:
Learning Focus: You concentrate on React concepts, not build configuration. Once you understand React, you’ll easily set up projects from scratch.
We’ll use the provided minimal app as our foundation
See GitHub repo for Quickstart instructions. With Docker and devcontainer support all set up for you including Frontend and Backend and Database.
# Start development (opens both frontend and backend)
npm run dev
# Frontend: http://localhost:5173
# Backend: http://localhost:4000 (we'll use next session)What you get:
fullstack-minimal-app/
├── frontend/ ← React app (Vite + React)
│ ├── src/
│ │ ├── App.jsx ← Main component
│ │ ├── main.jsx ← Entry point
│ │ └── components/ ← Our components go here
│ └── package.json
├── backend/ ← Node.js API (next session)
└── package.json ← Root scripts and dependencies
VS Code Extensions:
When You’ll have understood the basics, you can use AI to help generate components and boilerplate code.
Context: React functional component for [purpose]
Task: Create component that [specific functionality]
Constraints: Modern React hooks, Tailwind CSS
Output: Complete JSX componentfor exemple :
Only three core concepts to master:
A React component is a function that returns JSX
WelcomeMessage multiple timesIn JSX, you can embed any JavaScript expression inside {}:
// Variables
// {title} is a JavaScript variable
// If title = "Welcome to React!"
// Returns <h1>Welcome to React!</h1>
<h1>{title}</h1>
// Function calls
// {formatDate} is a JavaScript function
// if date is a Date object
// Returns formatted date string
<p>{formatDate(date)}</p>
// Array methods
// if products = [{id: 1, name: 'Item 1'}, {id: 2, name: 'Item 2'}]
// Returns list of product names
{products.map(p => <div key={p.id}>{p.name}</div>)}<div> or React Fragment <>...</>.JSX lets you write HTML-like syntax in JavaScript
function UserProfile() {
const name = "Alice Johnson";
const age = 25;
const isOnline = true;
return (
<div className="user-card">
{/* JavaScript expressions in {} */}
<h2>Welcome, {name}!</h2>
<p>Age: {age}</p>
{/* Conditional rendering */}
{isOnline && (
<span className="status online">🟢 Online</span>
)}
{/* Self-closing tags need / */}
<img src={`/avatar/${name}.jpg`} alt="Profile" />
<br />
{/* className not class */}
<button className="btn-primary">
Follow
</button>
</div>
);
}| HTML | JSX | Why? | Explanation |
|---|---|---|---|
class |
className |
class is reserved in JS |
Applies CSS classes to an element (maps to element.className). |
for |
htmlFor |
for is reserved in JS |
Associates a label with an input element (sets htmlFor attribute). |
onclick |
onClick |
camelCase convention | Attaches a click event handler function to the element. |
style="color: red" |
style={{color: 'red'}} |
JS object syntax | Sets inline styles using a JavaScript object (applies CSS properties). |
Props make components reusable by passing data into them
ProductCard component that accepts props for name, price, image, and inStock status.function ProductCard({ name, price, image, inStock }) {
return (
<div className="border rounded-lg p-4 shadow-md">
<img src={image} alt={name} className="w-full h-48 object-cover rounded" />
<h3 className="text-lg font-semibold mt-2">{name}</h3>
<p className="text-xl font-bold text-green-600">${price}</p>
{inStock ? (
<button className="w-full bg-blue-600 text-white py-2 rounded mt-2">
Add to Cart
</button>
) : (
<button className="w-full bg-gray-400 text-white py-2 rounded mt-2" disabled>
Out of Stock
</button>
)}
</div>
);
}function ProductGrid() {
return (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<ProductCard
name="Wireless Headphones"
price={99.99}
image="/images/headphones.jpg"
inStock={true}
/>
<ProductCard
name="Bluetooth Speaker"
price={79.99}
image="/images/speaker.jpg"
inStock={false}
/>
<ProductCard
name="Smart Watch"
price={299.99}
image="/images/watch.jpg"
inStock={true}
/>
</div>
);
}Props Pattern: Define once, use with different data!
Generate a Review Card Component
Prompt for AI:
Context: React component for displaying product reviews
Task: Create a ReviewCard component with these props:
- author (string): reviewer name
- rating (number): 1-5 stars
- title (string): review title
- content (string): review text
- date (string): review date
- source (string): "Amazon" | "BestBuy" | "Walmart"
Requirements:
- Display star rating as ★ symbols
- Show source with colored badge (Amazon=orange, BestBuy=blue, Walmart=green)
- Responsive design with Tailwind CSS
- Modern functional component syntax
Output: Complete ReviewCard.jsx component
After AI generates: 1. Create the component in frontend/src/components/ReviewCard.jsx 2. Test it in your App component 3. Try it with different prop values
State = data that can change and triggers UI updates
useState hookimport { useState } from 'react';
function Counter() {
// [value, setter] = useState(initialValue)
// value = current state
// setCount = function to update state
const [count, setCount] = useState(0);
return (
<div className="text-center p-4">
<h2 className="text-2xl mb-4">Count: {count}</h2>
<div className="space-x-2">
<button
onClick={() => setCount(count - 1)}
className="px-4 py-2 bg-red-500 text-white rounded"
>
-1
</button>
<button
onClick={() => setCount(count + 1)}
className="px-4 py-2 bg-green-500 text-white rounded"
>
+1
</button>
<button
onClick={() => setCount(0)}
className="px-4 py-2 bg-gray-500 text-white rounded"
>
Reset
</button>
</div>
</div>
);
}setCount, not count = 5)The problem: React doesn’t know when regular variables change, so it can’t re-render the UI.
The solution: useState tells React “this value matters, re-render when it changes!”
React handles events with camelCase: onClick, onChange, onSubmit
React controls form inputs = “Controlled Components”
useStatevalue is tied to state, and onChange updates the statefunction ProductSearch() {
const [term, setTerm] = useState('');
const handleSubmit = (e) => {
e.preventDefault(); // Prevent page reload
console.log('Search:', term);
// here add code to do something with the search term
// e.g. call an API to fetch search results
// and then update state with results, so the UI updates
};
return (
<form onSubmit={handleSubmit} className="max-w-md mx-auto p-4">
<label className="block text-sm font-medium mb-1">Search</label>
<div className="flex gap-2">
<input
value={term}
onChange={e => setTerm(e.target.value)}
className="flex-1 border rounded px-3 py-2"
placeholder="Type product name..."
aria-label="Search products"
/>
<button className="bg-blue-600 text-white px-4 py-2 rounded" type="submit">Go</button>
</div>
</form>
);
}Pattern: value={state} + onChange={setState} = Controlled Input
🎯 AI will generate this for you
Exercise: Build a “Product Filter” form component with: - Text input for search term - Checkbox for “In stock only” - Range slider for price (0-1000) - Display all current filter values below the form
Why this pattern?: React is the “single source of truth” for form data. This makes it easy to validate, submit, or reset forms programmatically.
useEffect is a React hook for managing side effects (e.g. data fetching, subscriptions)await and async are used for asynchronous callimport { useState, useEffect } from 'react';
function ProductList() {
const [names, setNames] = useState([]);
useEffect(() => {
// To avoid setting state on unmounted component
let mounted = true;
(async () => {
try {
const res = await fetch('http://localhost:4000/api/products');
if (!res.ok) throw new Error('fetch failed');
const data = await res.json();
if (mounted) setNames(data.map(p => p.name));
} catch (err) {
if (mounted) setNames([]);
}
})();
return () => { mounted = false; };
}, []);
return (
<ul className="list-disc pl-5">
{names.length === 0 ? (
<li className="text-sm text-gray-500">No products (or server not running)</li>
) : (
names.map((n, i) => <li key={i}>{n}</li>)
)}
</ul>
);
}frontend/src/components/ in the repository to inspect sample components we use in class.What You’ve Learned Today:
React Fundamentals ✅
Practical Skills ✅
Application Structure ✅
AI-Assisted Development ✅
E. Bruno - React Frontend Development