React Frontend Development

Building Interactive UIs with Modern React

Universitรฉ de Toulon

LIS UMR CNRS 7020

2025-10-12

React Frontend Development ๐Ÿš€

2-Hour Focus: Components โ†’ State โ†’ Real Application

๐ŸŽฏ Todayโ€™s Mission

What Weโ€™re Building (2 Hours)

Hour 1: React Fundamentals (components, JSX, props, basic state)
Hour 2: Interactive Features (events, forms, data fetching, real app structure)

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

๐Ÿ—บ๏ธ The Learning Path

Hour 1: REACT FOUNDATIONS       Hour 2: INTERACTIVE FEATURES
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Why React?      โ”‚           โ”‚ Event Handling  โ”‚
โ”‚ JSX & Componentsโ”‚    โ†’      โ”‚ Forms & Input   โ”‚
โ”‚ Props Passing   โ”‚           โ”‚ API Integration โ”‚
โ”‚ Basic State     โ”‚           โ”‚ Complete App!   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜           โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
   Foundation Ready              Production Ready

Hour 1: React Foundations

0:00 - 1:00

๐Ÿ’ก Why React? (The JavaScript Pain)

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โ€

๐Ÿš€ React in the Real World

What React Solves

  • Component Reusability: Write once, use everywhere
  • State Management: UI updates automatically
  • Virtual DOM: Efficient updates
  • Developer Experience: Great tools and ecosystem
  • Community: Huge library ecosystem

Industry Usage

  • Netflix: Entire streaming interface
  • Instagram: Web platform
  • Airbnb: Booking and host platforms
  • Uber: Driver and rider apps
  • Discord: Chat interface

Why Youโ€™re Learning React

graph TD
    A[Learn React] --> B[Build Frontend]
    B --> C[Connect to Node/Express]
    C --> D[Full-Stack Developer! ๐ŸŽ‰]

Job Market: React is the #1 frontend framework
This Course: React + Node.js = Complete full-stack skills

Our Project Today: Product review aggregator frontend that will connect to Express backend next session!

๐Ÿ”ง Setup: fullstack-minimal-app

Weโ€™ll use the provided minimal app as our foundation

# Clone and setup
git clone https://github.com/your-repo/fullstack-minimal-app
cd fullstack-minimal-app

# Install dependencies
npm install

# 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

๐Ÿค– AI Development Setup

VS Code Extensions: - GitHub Copilot - ES7+ React snippets - Tailwind CSS IntelliSense

AI Prompting Pattern:

Context: React functional component for [purpose]
Task: Create component that [specific functionality]
Constraints: Modern React hooks, Tailwind CSS
Output: Complete JSX component

๐Ÿงฉ Components: The Building Blocks

A React component is a function that returns JSX

Simple Component

function WelcomeMessage() {
  return (
    <div className="p-4 bg-blue-50 rounded">
      <h1 className="text-2xl font-bold text-blue-800">
        Welcome to React! ๐Ÿ‘‹
      </h1>
      <p className="text-blue-600">
        You're building with components now!
      </p>
    </div>
  );
}

Using Components

function App() {
  return (
    <div className="container mx-auto p-4">
      <WelcomeMessage />
      <WelcomeMessage />
      <WelcomeMessage />
    </div>
  );
}

Key Concepts: - Components are reusable (use multiple times) - Components are composable (nest inside each other) - Components use JSX (looks like HTML, but itโ€™s JavaScript)

๐Ÿ“ JSX: JavaScript + HTML

JSX lets you write HTML-like syntax in JavaScript

JSX Rules

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 vs JSX Differences

HTML JSX Why?
class className class is reserved in JS
for htmlFor for is reserved in JS
onclick onClick camelCase convention
style="color: red" style={{color: 'red'}} JS object syntax

Expression Examples

// Variables
<h1>{title}</h1>

// Function calls
<p>{formatDate(date)}</p>

// Ternary operator
<span>{isVip ? 'โญ VIP' : 'Member'}</span>

// Array methods
{products.map(p => <div key={p.id}>{p.name}</div>)}

๐Ÿ“ฆ Props: Passing Data

Props make components reusable by passing data into them

Creating a Component with Props

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>
  );
}

Using the Component with Different Data

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!

๐Ÿค– AI Practice: Product Card Component

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: Making Components Interactive

State = data that can change and triggers UI updates

useState Hook

import { useState } from 'react';

function Counter() {
  // [value, setter] = useState(initialValue)
  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>
  );
}

Key Points: - Always use the setter function (setCount, not count = 5) - State updates trigger re-render - Each component has its own state

๐ŸŽฏ Toggle State Example

function ProductDetails() {
  const [showDetails, setShowDetails] = useState(false);
  const [quantity, setQuantity] = useState(1);
  
  return (
    <div className="border p-4 rounded">
      <h3 className="text-xl font-bold">Wireless Headphones</h3>
      <p className="text-green-600 font-semibold">$99.99</p>
      
      <button 
        onClick={() => setShowDetails(!showDetails)}
        className="mt-2 px-4 py-2 bg-blue-500 text-white rounded"
      >
        {showDetails ? 'Hide Details' : 'Show Details'}
      </button>
      
      {showDetails && (
        <div className="mt-4 p-3 bg-gray-50 rounded">
          <h4 className="font-semibold">Product Details:</h4>
          <ul className="list-disc list-inside mt-2">
            <li>Wireless Bluetooth 5.0</li>
            <li>30-hour battery life</li>
            <li>Active noise cancellation</li>
          </ul>
        </div>
      )}
      
      <div className="mt-4">
        <label className="block text-sm font-medium">Quantity:</label>
        <input 
          type="number"
          value={quantity}
          onChange={(e) => setQuantity(parseInt(e.target.value))}
          min="1"
          className="mt-1 border rounded px-3 py-2"
        />
      </div>
    </div>
  );
}

๐Ÿƒ Quick Practice: State Components

Create a simple component with state:

Option 1: Like/Unlike button with counter Option 2: Show/hide product reviews section
Option 3: Color theme switcher

Use AI to generate, then test in your app!

โœ… Hour 1 Checkpoint

Before break, you should have: - โœ… Understanding of components and JSX - โœ… Created components with props - โœ… Used useState for interactive features - โœ… Built at least one working component

Hour 2 Preview: Forms, API calls, complete application!

Hour 2: Interactive Features

1:00 - 2:00

๐ŸŽฎ Event Handling

React handles events with camelCase: onClick, onChange, onSubmit

Common Event Patterns

function InteractiveDemo() {
  const [message, setMessage] = useState('Click something!');
  const [inputValue, setInputValue] = useState('');
  
  const handleButtonClick = () => {
    setMessage('Button was clicked! ๐ŸŽ‰');
  };
  
  const handleInputChange = (event) => {
    setInputValue(event.target.value);
    setMessage(`You typed: ${event.target.value}`);
  };
  
  const handleMouseEnter = () => {
    setMessage('Mouse entered the area! ๐Ÿญ');
  };
  
  return (
    <div className="p-4 space-y-4">
      <p className="text-lg font-semibold">{message}</p>
      
      <button 
        onClick={handleButtonClick}
        className="px-4 py-2 bg-blue-500 text-white rounded"
      >
        Click Me
      </button>
      
      <input
        type="text"
        value={inputValue}
        onChange={handleInputChange}
        placeholder="Type something..."
        className="border rounded px-3 py-2"
      />
      
      <div
        onMouseEnter={handleMouseEnter}
        className="p-4 bg-yellow-100 rounded cursor-pointer"
      >
        Hover over me!
      </div>
    </div>
  );
}

๐Ÿ“ Forms & Controlled Inputs

React controls form inputs = โ€œControlled Componentsโ€

Product Search Form

function ProductSearch() {
  const [searchTerm, setSearchTerm] = useState('');
  const [category, setCategory] = useState('all');
  const [priceRange, setPriceRange] = useState('any');
  const [results, setResults] = useState([]);
  
  const handleSubmit = (event) => {
    event.preventDefault(); // Important: prevent page reload!
    
    console.log('Searching for:', {
      searchTerm,
      category,
      priceRange
    });
    
    // Simulate search results
    setResults([
      `Results for "${searchTerm}" in ${category}`,
      `Price range: ${priceRange}`,
      `Found 3 products matching your criteria`
    ]);
  };
  
  return (
    <div className="max-w-md mx-auto p-4">
      <form onSubmit={handleSubmit} className="space-y-4">
        <div>
          <label className="block text-sm font-medium mb-1">
            Search Products:
          </label>
          <input
            type="text"
            value={searchTerm}
            onChange={(e) => setSearchTerm(e.target.value)}
            placeholder="Enter product name..."
            className="w-full border rounded px-3 py-2"
            required
          />
        </div>
        
        <div>
          <label className="block text-sm font-medium mb-1">
            Category:
          </label>
          <select
            value={category}
            onChange={(e) => setCategory(e.target.value)}
            className="w-full border rounded px-3 py-2"
          >
            <option value="all">All Categories</option>
            <option value="electronics">Electronics</option>
            <option value="clothing">Clothing</option>
            <option value="books">Books</option>
          </select>
        </div>
        
        <div>
          <label className="block text-sm font-medium mb-1">
            Price Range:
          </label>
          <select
            value={priceRange}
            onChange={(e) => setPriceRange(e.target.value)}
            className="w-full border rounded px-3 py-2"
          >
            <option value="any">Any Price</option>
            <option value="under-50">Under $50</option>
            <option value="50-100">$50 - $100</option>
            <option value="over-100">Over $100</option>
          </select>
        </div>
        
        <button
          type="submit"
          className="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700"
        >
          Search Products
        </button>
      </form>
      
      {results.length > 0 && (
        <div className="mt-4 p-3 bg-green-50 rounded">
          <h3 className="font-semibold">Search Results:</h3>
          <ul className="mt-2">
            {results.map((result, index) => (
              <li key={index} className="text-sm">{result}</li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}

Pattern: value={state} + onChange={setState} = Controlled Input

๐ŸŒ API Integration with useEffect

useEffect runs code after render (perfect for API calls)

Fetching Data on Component Mount

import { useState, useEffect } from 'react';

function ProductList() {
  const [products, setProducts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  // Runs once when component mounts
  useEffect(() => {
    const fetchProducts = async () => {
      try {
        setLoading(true);
        const response = await fetch('http://localhost:4000/api/products');
        
        if (!response.ok) {
          throw new Error('Failed to fetch products');
        }
        
        const data = await response.json();
        setProducts(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };
    
    fetchProducts();
  }, []); // Empty dependency array = run once on mount
  
  if (loading) {
    return (
      <div className="text-center p-8">
        <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto"></div>
        <p className="mt-2">Loading products...</p>
      </div>
    );
  }
  
  if (error) {
    return (
      <div className="text-center p-8 text-red-600">
        <p>Error: {error}</p>
        <button 
          onClick={() => window.location.reload()}
          className="mt-2 px-4 py-2 bg-red-600 text-white rounded"
        >
          Try Again
        </button>
      </div>
    );
  }
  
  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
      {products.map(product => (
        <div key={product.id} className="border rounded-lg p-4 shadow">
          <h3 className="text-lg font-semibold">{product.name}</h3>
          <p className="text-green-600 font-bold">${product.price}</p>
          <p className="text-gray-600 text-sm mt-1">{product.description}</p>
          <button className="mt-2 w-full bg-blue-600 text-white py-2 rounded">
            View Details
          </button>
        </div>
      ))}
    </div>
  );
}

๐Ÿค– AI Practice: Review Fetcher Component

Build a Review Fetcher

Prompt for AI:

Context: React component for fetching product reviews
Task: Create ReviewFetcher component that:

1. Has a "Fetch Reviews" button
2. When clicked, calls POST /api/products/:id/fetch
3. Shows loading state while fetching
4. Displays success message with review count
5. Handles errors gracefully
6. Uses useState and async/await

Props:
- productId (string): ID of product to fetch reviews for

Requirements:
- Loading spinner during fetch
- Success/error messages
- Tailwind CSS styling
- Modern React hooks

Output: Complete React component

Test with: Mock API call (will work with real backend next session)

๐Ÿ—๏ธ Building the Complete App Structure

Letโ€™s structure our review aggregator application

App Component Structure

// App.jsx
import { useState } from 'react';
import ProductHeader from './components/ProductHeader';
import ReviewFetcher from './components/ReviewFetcher';
import ReviewStats from './components/ReviewStats';
import ReviewList from './components/ReviewList';

function App() {
  const [reviews, setReviews] = useState([]);
  const [stats, setStats] = useState(null);
  const productId = "sample-product-1"; // In real app, this comes from URL
  
  const handleReviewsFetched = (newReviews, newStats) => {
    setReviews(newReviews);
    setStats(newStats);
  };
  
  return (
    <div className="min-h-screen bg-gray-50">
      <div className="container mx-auto px-4 py-8">
        <ProductHeader productId={productId} />
        
        <div className="grid grid-cols-1 lg:grid-cols-3 gap-8 mt-8">
          {/* Left Column: Actions and Stats */}
          <div className="lg:col-span-1 space-y-6">
            <ReviewFetcher 
              productId={productId}
              onReviewsFetched={handleReviewsFetched}
            />
            
            {stats && (
              <ReviewStats stats={stats} />
            )}
          </div>
          
          {/* Right Column: Review List */}
          <div className="lg:col-span-2">
            <ReviewList reviews={reviews} />
          </div>
        </div>
      </div>
    </div>
  );
}

export default App;

Component Organization

frontend/src/
โ”œโ”€โ”€ components/
โ”‚   โ”œโ”€โ”€ ProductHeader.jsx      โ† Product info display
โ”‚   โ”œโ”€โ”€ ReviewFetcher.jsx      โ† Fetch reviews button
โ”‚   โ”œโ”€โ”€ ReviewStats.jsx        โ† Statistics visualization
โ”‚   โ”œโ”€โ”€ ReviewList.jsx         โ† List of reviews
โ”‚   โ””โ”€โ”€ ReviewCard.jsx         โ† Individual review display
โ”œโ”€โ”€ hooks/
โ”‚   โ””โ”€โ”€ useReviews.js          โ† Custom hook for review logic
โ”œโ”€โ”€ services/
โ”‚   โ””โ”€โ”€ api.js                 โ† API calls
โ””โ”€โ”€ App.jsx                    โ† Main app component

๐ŸŽฏ Complete Example: Review Stats Component

function ReviewStats({ stats }) {
  if (!stats) {
    return (
      <div className="bg-white rounded-lg shadow p-6">
        <h3 className="text-lg font-semibold mb-4">Review Statistics</h3>
        <p className="text-gray-500">No statistics available yet.</p>
      </div>
    );
  }
  
  const { overallAverage, totalReviews, sourceBreakdown, ratingHistogram } = stats;
  
  return (
    <div className="bg-white rounded-lg shadow p-6">
      <h3 className="text-lg font-semibold mb-4">Review Statistics</h3>
      
      {/* Overall Stats */}
      <div className="text-center mb-6">
        <div className="text-3xl font-bold text-blue-600">
          {overallAverage.toFixed(1)}โ˜…
        </div>
        <p className="text-gray-600">{totalReviews} total reviews</p>
      </div>
      
      {/* Source Breakdown */}
      <div className="mb-6">
        <h4 className="font-medium mb-2">By Source:</h4>
        {sourceBreakdown.map(source => (
          <div key={source.name} className="flex justify-between items-center py-1">
            <span className="text-sm">{source.name}</span>
            <span className="text-sm font-semibold">
              {source.average.toFixed(1)}โ˜… ({source.count})
            </span>
          </div>
        ))}
      </div>
      
      {/* Rating Histogram */}
      <div>
        <h4 className="font-medium mb-2">Rating Distribution:</h4>
        {[5, 4, 3, 2, 1].map(rating => {
          const count = ratingHistogram[rating] || 0;
          const percentage = totalReviews > 0 ? (count / totalReviews) * 100 : 0;
          
          return (
            <div key={rating} className="flex items-center mb-1">
              <span className="text-sm w-8">{rating}โ˜…</span>
              <div className="flex-1 bg-gray-200 rounded-full h-2 mx-2">
                <div
                  className="bg-blue-600 h-2 rounded-full"
                  style={{ width: `${percentage}%` }}
                ></div>
              </div>
              <span className="text-sm w-8 text-right">{count}</span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

๐Ÿ Session Wrap-up

What Youโ€™ve Learned Today:

React Fundamentals โœ…

  • Components and JSX syntax
  • Props for data passing
  • State with useState hook
  • Event handling patterns
  • Controlled form inputs
  • useEffect for side effects

Practical Skills โœ…

  • Building reusable components
  • Managing application state
  • Handling user interactions
  • API integration patterns
  • Error handling and loading states

Application Structure โœ…

  • Component organization
  • Data flow patterns
  • State management strategies
  • Real-world app architecture

AI-Assisted Development โœ…

  • Effective prompting techniques
  • Code verification skills
  • Iterative development process
  • Debugging generated code

Next Session Preview: Build the Node.js/Express backend that will power this React frontend!

๐Ÿ“š Practice Session Preview

Immediately after this lecture: 1-hour hands-on practice building your review aggregator frontend components using the patterns learned today.

What youโ€™ll build: - Complete React frontend for the Multi-Source Product Review Aggregator - Components for displaying and fetching reviews - Integration with mock API (preparing for real backend) - Responsive design with Tailwind CSS

This prepares you for: Next sessionโ€™s backend development where youโ€™ll build the Express API that serves this frontend!

๐ŸŽ‰ Youโ€™re Now a React Developer!

Key Achievements: - โšก Built interactive UIs with components - ๐Ÿ”„ Managed state and handled events - ๐ŸŒ Integrated with APIs using useEffect - ๐ŸŽจ Created responsive layouts - ๐Ÿค– Used AI effectively for development - ๐Ÿ—๏ธ Structured a real application

Next Steps: Practice building the review aggregator, then learn Node.js to create the backend! ๐Ÿš€