React Basics

Session 2 — Events, Conditional Rendering & Lists

⏱ 45 minutes
📚 Beginner
🎯 Interactivity
Scroll to begin ▼
Part 1 · Overview

Session Agenda

We'll make React apps truly interactive — responding to clicks, showing/hiding content, and rendering dynamic lists. By the end, you'll build a working todo list.

0 – 10 min

Event Handling

onClick, onChange, onSubmit — how React handles user interactions.

10 – 20 min

Conditional Rendering

Show or hide elements based on state using if, ternary, and &&.

20 – 30 min

Lists & Keys

Render arrays of data with .map() and why keys matter.

30 – 40 min

Building a Todo List

Combine events, state, and lists into a real mini-project.

40 – 45 min

Recap & Quick Quiz

Review key concepts and test what you've learned.

Part 2 · Interactivity

Event Handling

In React, you attach events directly to JSX elements using camelCase props like onClick, onChange, and onSubmit.

Basic Events
function ButtonDemo() {
  // Handler is just a function
  function handleClick() {
    alert('Button was clicked!')
  }

  return (
    <div>
      {/* Pass the function, don't call it */}
      <button onClick={handleClick}>Click me</button>

      {/* Or use an inline arrow function */}
      <button onClick={() => alert('Hello!')}>Inline</button>
    </div>
  )
}
⚠️ Common Mistake

Write onClick={handleClick} not onClick={handleClick()}. The second version calls the function immediately when the component renders — not on click.

🖱️

onClick

Fires when the user clicks an element. Most common event in React.

⌨️

onChange

Fires on every keystroke in an input. Used to track text field values.

📋

onSubmit

Fires when a form is submitted. Always call e.preventDefault() inside.

🎯

onFocus / onBlur

Fires when an element gains or loses focus. Useful for validation feedback.

Part 3 · The Event Object

Working with the Event Object

React wraps native browser events in a SyntheticEvent — it works the same way but works consistently across all browsers.

Reading Input Value
import { useState } from 'react'

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

  // e is the event object — e.target is the input element
  function handleChange(e) {
    setText(e.target.value)
  }

  return (
    <div>
      <input
        value={text}
        onChange={handleChange}
        placeholder="Type something..."
      />
      <p>You typed: {text}</p>
      <p>Length: {text.length} characters</p>
    </div>
  )
}
💡 Key Properties

e.target.value — the current value of an input.
e.target.checked — whether a checkbox is checked.
e.preventDefault() — stops the default browser behavior (e.g., form page reload).

Part 4 · Show & Hide

Conditional Rendering

React lets you conditionally show parts of the UI based on state. There are three common patterns.

3 Ways to Conditionally Render
function ConditionalDemo() {
  const [isLoggedIn, setIsLoggedIn] = useState(false)
  const [count, setCount] = useState(0)

  return (
    <div>

      {/* Pattern 1: if/else with early return */}
      function Status() {
        if (isLoggedIn) return <p>Welcome back!</p>
        return <p>Please log in.</p>
      }

      {/* Pattern 2: Ternary operator — use for either/or */}
      {isLoggedIn
        ? <button>Logout</button>
        : <button>Login</button>
      }

      {/* Pattern 3: && operator — use to show or show nothing */}
      {count > 5 && <p>Count is getting high!</p>}

    </div>
  )
}
Pattern When to Use Example
if / else Complex logic, multiple branches Show different pages based on user role
Ternary ? : Two options, inline in JSX Login / Logout button
&& operator Show something or nothing Show error message if there's an error

🔴 Live Demo — Toggle Visibility

Click the button to toggle the message (simulates conditional rendering):

Part 5 · Dynamic Lists

Lists & Keys

To render a list of items, use JavaScript's .map() method. Each item needs a unique key prop so React can track changes efficiently.

Rendering a List
const fruits = ['Apple', 'Banana', 'Cherry']

function FruitList() {
  return (
    <ul>
      {fruits.map((fruit, index) => (
        <li key={index}>{fruit}</li>
      ))}
    </ul>
  )
}

// With objects — use a unique ID as key
const users = [
  { id: 1, name: 'Ahmed' },
  { id: 2, name: 'Sara'  },
]

function UserList() {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  )
}
⚠️ Keys Must Be Unique & Stable

Prefer using a real ID from your data as the key. Using array index as key works for static lists, but can cause bugs if items are added, removed, or reordered.

1

Start with an array of data

This is your source of truth — could be from state, props, or fetched from an API.

2

Use .map() to transform to JSX

Each item in the array becomes a JSX element. The callback returns JSX.

3

Always add a key prop

React uses keys to identify which items changed, were added, or were removed.

Part 6 · Mini Project

Building a Todo List

Let's combine everything: state for the list, events for adding/removing items, and .map() for rendering them.

TodoApp.jsx
import { useState } from 'react'

function TodoApp() {
  const [todos, setTodos] = useState([
    { id: 1, text: 'Learn React', done: false }
  ])
  const [input, setInput] = useState('')

  function addTodo() {
    if (!input.trim()) return
    setTodos([...todos, { id: Date.now(), text: input, done: false }])
    setInput('')
  }

  function toggleTodo(id) {
    setTodos(todos.map(t =>
      t.id === id ? { ...t, done: !t.done } : t
    ))
  }

  function deleteTodo(id) {
    setTodos(todos.filter(t => t.id !== id))
  }

  return (
    <div>
      <h2>My Todos ({todos.filter(t => !t.done).length} left)</h2>
      <input
        value={input}
        onChange={e => setInput(e.target.value)}
        onKeyDown={e => e.key === 'Enter' && addTodo()}
        placeholder="Add a task..."
      />
      <button onClick={addTodo}>Add</button>

      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            <span
              onClick={() => toggleTodo(todo.id)}
              style={{ textDecoration: todo.done ? 'line-through' : 'none' }}
            >{todo.text}</span>
            <button onClick={() => deleteTodo(todo.id)}>✕</button>
          </li>
        ))}
      </ul>
    </div>
  )
}

🔴 Live Demo — Try the Todo List!

Add tasks, click to complete, hit ✕ to delete:

💡 Spread Operator in State Updates

[...todos, newTodo] creates a new array with all existing items plus the new one. React requires new array/object references to detect state changes — never mutate state directly.

Part 7 · Wrap-Up

Recap & Quick Quiz

Let's review the key concepts from today's session.

✅

Events

React uses camelCase event props like onClick and onChange. Pass the function reference, don't call it.

✅

Conditional Rendering

Use ternary for either/or, && for show-or-nothing, and if/else for complex logic.

✅

Lists with .map()

Transform arrays of data into arrays of JSX elements.

✅

Keys

Every list item needs a unique key prop. Prefer IDs over array indexes.

🧪 Quiz — Question 1 of 3

What's wrong with onClick={handleClick()}?

🧪 Quiz — Question 2 of 3

Which operator renders something OR nothing (not an else branch)?

🧪 Quiz — Question 3 of 3

Why does React require a key prop on list items?
🎯 What's Next?

In Session 3, we'll learn useEffect — how to run side effects like fetching data from APIs, handling loading states, and cleaning up effects.