React Frontend Development

Building Interactive UIs with Modern React

Université de Toulon

LIS UMR CNRS 7020

2025-10-15

React Frontend Development 🚀

By the end of this session, you will be able to:

  1. Explain React’s component-based architecture and its advantages over vanilla JavaScript DOM manipulation
  2. Build and compose functional React components using JSX and props
  3. Manage state and handle user events in React applications
  4. Integrate external API data using React hooks (useState, useEffect)
  5. Structure a real-world React project for maintainability and scalability

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.

🎯 Today’s Mission

What We’re Building

  • Part 1: React Fundamentals (components, JSX, props, basic state)
  • Part 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

💡 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”

🎯 Real-World Software Engineering Challenge

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:

  • Maintainability: Components isolate complexity
  • Scalability: Add features without rewriting existing code
  • Testability: Test components in isolation
  • Collaboration: Teams can work on different components simultaneously

🚀 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

💼 Industry Context

React’s component model has become the industry standard for building modern web applications. Understanding React prepares you for:

  • Job Market: React is the #1 frontend framework (used by 40%+ of web developers)
  • Next.js (React with server-side rendering)
  • React Native (Mobile app development)
  • Remix, Gatsby, and other React-based frameworks

Learning React is not just about one library—it’s about understanding the component-based architecture pattern that dominates modern web development.

🛠️ Setup and Development Tools

What You Need to Run React Locally

Essential Tools:

  1. Node.js (v18+ recommended)
    • JavaScript runtime for running development tools
    • Includes npm (Node Package Manager)
    • Download: nodejs.org
  2. npm (comes with Node.js)
    • Package manager for installing React and dependencies
    • Used to run development scripts
  3. Vite (build tool)
    • Fast development server with Hot Module Replacement (HMR)
    • Modern alternative to Create React App
    • Build tool optimized for React development

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 dev

For 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:

  • ✅ React + Vite pre-configured
  • ✅ Tailwind CSS for styling
  • ✅ Node.js/Express backend (ready for next session)
  • ✅ Database integration setup
  • ✅ Project structure following industry best practices

Learning Focus: You concentrate on React concepts, not build configuration. Once you understand React, you’ll easily set up projects from scratch.

🔧 Setup: fullstack-minimal-app

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

🤖 AI Development Setup

VS Code Extensions:

  • GitHub Copilot and Copilot Chat
  • ES7+ React snippets
  • Tailwind CSS IntelliSense

When You’ll have understood the basics, you can use AI to help generate components and boilerplate code.

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

for exemple :

Context: React component for displaying product reviews
Task: Create a ReviewCard component with these props:
- review: { id, user, comment, rating }
Constraints: Modern React hooks, Tailwind CSS
Output: Complete JSX component

The 3 main concepts of React

  • Only three core concepts to master:

    • Components: Reusable building blocks of UI
    • Props: Data passed into components
    • State: Data that changes over time and triggers UI updates

🧩 Components: The Building Blocks

A React component is a function that returns JSX

  • JSX = JavaScript + XML (HTML-like syntax)
  • Components are reusable, composable pieces of UI
  • The following examples define a simple component that displays a welcome message.
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

  • Use JSX components like HTML tags
  • In the main App component, you can include WelcomeMessage multiple times
  • You can also nest components inside each other
function App() {
  return (
    <div className="container mx-auto p-4">
      <WelcomeMessage />
      <WelcomeMessage />
      <WelcomeMessage />
    </div>
  );
}

Component 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) : easy to read and write

Expression Examples

In JSX, you can embed any JavaScript expression inside {}:

  • The code will be evaluated and the result inserted into the HTML
  • On the client side, this allows dynamic rendering based on variables, function calls, …
// 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>)}

⚠️ In JSX, Always Return a Single Root Element

  • A component must return a single root element.
  • Wrap multiple elements in a <div> or React Fragment <>...</>.
// ❌ Wrong
return (
  <h1>Title</h1>
  <p>Content</p>
)
// ✅ Correct
return (
  <>
    <h1>Title</h1>
    <p>Content</p>
  </>
)

📝 JSX: JavaScript + HTML

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

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: Passing Data

Props make components reusable by passing data into them

  • A JSX attribute is like a function argument
  • Props are passed to components in a similar way to how arguments are passed to functions
  • In the example below, we create a 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>
  );
}

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

  • State is managed with the useState hook
  • Each piece of state is independent
  • State updates cause the component to re-render with new values
  • State is local to the component (not shared unless passed via props)
  • the following example shows a simple counter component using state.
import { 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>
  );
}

Key Points in State Management

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

🧠 Why not use regular variables?

// ❌ This won't work!
function BrokenCounter() {
  let count = 0;
  
  const increment = () => {
    count = count + 1; // Updates variable...
    console.log(count); // Logs correctly...
    // But UI doesn't update! 😢
  };
  
  return <button onClick={increment}>Count: {count}</button>;
}
// ✅ This works!
function WorkingCounter() {
  const [count, setCount] = useState(0);
  
  const increment = () => {
    setCount(count + 1); // React knows to re-render!
  };
  
  return <button onClick={increment}>Count: {count}</button>;
}

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!”

🎮 Interactive Features : Event Handling

React handles events with camelCase: onClick, onChange, onSubmit

  • A component can respond to user actions via event handlers
  • Event handlers are functions passed to components as props
  • When the event occurs, the handler function is called
    • Event handlers receive an event object as an argument
    • Common events: click, change, submit, mouse enter/leave, key press
    • Exemple: when a button is clicked, update state

Minimal Event Example

function InteractiveDemo() {
  const [text, setText] = useState('');

  return (
    <div>
      <button onClick={() => alert('Clicked!')}>Click</button>
      <input value={text} onChange={e => setText(e.target.value)} placeholder="Type..." />
      <p>Current: {text}</p>
    </div>
  );
}

📝 Forms & Controlled Inputs

React controls form inputs = “Controlled Components”

  • Form inputs (text, select, checkbox) maintain their own state
  • In React, we control the input state via useState
  • The input’s value is tied to state, and onChange updates the state
  • This way, React is the “single source of truth” for form data

Product Search Form — Minimal

  • The following is a minimal product search form component with a controlled text input and a submit handler that logs the search term.
function 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.

🌐 API Integration with useEffect

  • useEffect is a React hook for managing side effects (e.g. data fetching, subscriptions)
  • useffect takes two arguments:
    • A function to run (the effect)
    • An array of dependencies (when to re-run the effect)
  • It runs after the component renders, making it ideal for API calls.
  • You can think of it as a way to perform actions “after” the component has rendered.

Fetching Data on Component Mount

  • The following example fetches a list of products from an API when the component mounts.
  • Fetch will call the API and store the results in state
  • The component re-renders with the fetched data
  • Note await and async are used for asynchronous call
  • The following is a minimal example of fetching product names from an API and displaying them in a list.
import { 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>
  );
}

A Minimal Example : Fullstack mini app

  • Browse the frontend components: see frontend/src/components/ in the repository to inspect sample components we use in class.
  • Read the project docs:

🏁 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