← Back to Module

React & State Management

CMM721: Web Application Development - Session 9

Birmingham Newman University

Lecturer: James Williams

Masters Level Conversion Course

3-hour session • 18 slides • 2 tasks • Interactive React demos

Session Timeline:

  • 10 min: Registration & waiting
  • 20 min: Opening slides
  • 45 min: Task 1
  • 15 min: Break/Catch up
  • 20 min: Secondary slides
  • 45 min: Task 2
  • Remaining: Self-study

Learning Objectives

  • Understand React component architecture
  • Work with JSX syntax
  • Manage component state with hooks
  • Handle props and data flow
  • Use useEffect for side effects
  • Understand Redux state management basics

What is React?

React: JavaScript library for building user interfaces
  • Component-Based: Build encapsulated components
  • Declarative: Describe what UI should look like
  • Virtual DOM: Efficient updates and rendering
  • Learn Once, Write Anywhere: React, React Native

Setup:

# Install Node.js, then:
npx create-react-app my-app
cd my-app
npm start

# Visit: http://localhost:3000

JSX Syntax

JSX: JavaScript XML - HTML-like syntax in JavaScript
// JSX
const element = <h1>Hello, CMM721!</h1>;

// With expressions
const name = 'Student';
const greeting = <h1>Hello, {name}!</h1>;

// With attributes
const button = <button className="btn" onClick={handleClick}>
  Click Me
</button>;

// Multi-line
const element = (
  <div>
    <h1>Title</h1>
    <p>Content</p>
  </div>
);

Function Components

// Simple component
function Welcome() {
  return <h1>Hello, World!</h1>;
}

// With props
function Welcome(props) {
  return <h1>Hello, {props.name}!</h1>;
}

// Arrow function
const Welcome = ({ name }) => {
  return <h1>Hello, {name}!</h1>;
};

// Usage
<Welcome name="James" />

🎯 Component Hierarchy

React Component Tree

App

Root component

Header

Navigation

Main

Content area

Footer

Site info

PostList

Fetch & display

PostItem

Single post

useState Hook

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
      <button onClick={() => setCount(count - 1)}>
        Decrement
      </button>
    </div>
  );
}
useState: Returns [value, setter function]

🎯 LIVE DEMO: Counter with State

Interactive Counter Component

0
Simulating React state updates with useState

Props

Props: Pass data from parent to child components
// Parent component
function App() {
  return (
    <div>
      <Greeting name="James" role="Lecturer" />
      <Greeting name="Student" role="Learner" />
    </div>
  );
}

// Child component
function Greeting({ name, role }) {
  return (
    <div>
      <h2>Hello, {name}!</h2>
      <p>Role: {role}</p>
    </div>
  );
}

Lists and Keys

function PostList() {
  const posts = [
    { id: 1, title: 'Django Tutorial' },
    { id: 2, title: 'React Basics' },
    { id: 3, title: 'REST APIs' }
  ];

  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
Keys: Help React identify which items changed

Task 1: Build React Components

Objective:

Create a blog interface using React components

Requirements:

  1. Create React app: npx create-react-app blog-app
  2. Build Header component with navigation
  3. Create PostList component displaying array of posts
  4. Create PostItem component for individual post
  5. Implement Counter component with useState
  6. Pass props from parent to child components
  7. Use .map() to render post list

Components:

  • App - Root component
  • Header - Site header
  • PostList - List container
  • PostItem - Single post card

useEffect Hook

import { useState, useEffect } from 'react';

function Posts() {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('http://localhost:8000/api/posts/')
      .then(response => response.json())
      .then(data => {
        setPosts(data);
        setLoading(false);
      });
  }, []); // Empty array = run once on mount

  if (loading) return <p>Loading...</p>;
  return <PostList posts={posts} />;
}

🎯 LIVE DEMO: Fetch Posts

Simulating useEffect Data Fetching

Click button to fetch posts...

useEffect Dependencies

// Run once on mount
useEffect(() => {
  fetchData();
}, []);

// Run when 'id' changes
useEffect(() => {
  fetchPost(id);
}, [id]);

// Run on every render (avoid!)
useEffect(() => {
  console.log('Component rendered');
});

// Cleanup function
useEffect(() => {
  const timer = setInterval(() => {
    console.log('Tick');
  }, 1000);

  return () => clearInterval(timer); // Cleanup
}, []);

Forms in React

function CreatePost() {
  const [title, setTitle] = useState('');
  const [content, setContent] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log({ title, content });
    // Send to API
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={title}
        onChange={(e) => setTitle(e.target.value)}
      />
      <textarea
        value={content}
        onChange={(e) => setContent(e.target.value)}
      />
      <button type="submit">Create Post</button>
    </form>
  );
}

Task 2: Fetch from Django API

Objective:

Connect React frontend to Django REST API

Requirements:

  1. Install axios: npm install axios
  2. Fetch posts from Django API on component mount
  3. Display loading state while fetching
  4. Show error message if fetch fails
  5. Create form to add new post (POST request)
  6. Implement delete button (DELETE request)
  7. Add CORS to Django: pip install django-cors-headers

API Endpoints:

  • GET http://localhost:8000/api/posts/
  • POST http://localhost:8000/api/posts/
  • DELETE http://localhost:8000/api/posts/:id/

Introduction to Redux

Redux: Predictable state container for JavaScript apps

Core Concepts:

  • Store: Single source of truth for app state
  • Actions: Plain objects describing what happened
  • Reducers: Pure functions that update state
  • Dispatch: Send actions to store

When to Use:

  • Large app with complex state
  • State shared across many components
  • Frequent state updates
  • Need for time-travel debugging

Redux Example

// Action
const increment = () => ({ type: 'INCREMENT' });

// Reducer
const counterReducer = (state = { count: 0 }, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    case 'DECREMENT':
      return { count: state.count - 1 };
    default:
      return state;
  }
};

// Create store
import { createStore } from 'redux';
const store = createStore(counterReducer);

// Dispatch action
store.dispatch(increment());

React Hooks vs Redux

useState/useContext (React):

  • ✅ Built into React
  • ✅ Simple for small/medium apps
  • ✅ Less boilerplate
  • ❌ Can become complex with deep nesting

Redux:

  • ✅ Centralized state management
  • ✅ Time-travel debugging
  • ✅ Middleware support
  • ❌ More boilerplate
  • ❌ Learning curve
Recommendation: Start with hooks, add Redux if needed

Best Practices

  • Component Structure: Keep components small and focused
  • Props vs State: Use props for data passed down, state for local data
  • Immutability: Never mutate state directly
  • Keys: Always provide unique keys in lists
  • useEffect cleanup: Clear timers/subscriptions
  • Conditional rendering: Use &&, ternary, or early returns
  • Code splitting: Use React.lazy() for large apps
  • PropTypes: Validate props (or use TypeScript)

Next Session: Web App Critique

  • Evaluating usability and UX
  • Performance analysis
  • Accessibility evaluation (WCAG)
  • Standards compliance
  • Security considerations
  • Ethical considerations in web development

Preparation: Find 2-3 web applications to analyze

Questions & Discussion

Contact: JWilliams@Staff.newman.ac.uk

Office Hours: By appointment

Resources: React Documentation, React Tutorial

Thank you for your attention!