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.