← Back to Chapters

Dynamic Lists and Filtering

⚛️ Dynamic Lists and Filtering

? Quick Overview

React Dynamic Lists map() filter()

Real-world applications often need dynamic lists — lists that can change when users add, remove, or filter items. In React, we manage these lists using component state (usually arrays) and array helper methods such as map(), filter(), and the spread operator [...array].

Mastering dynamic lists is essential for building interactive UIs like to-do apps, product search, or dashboards that respond to user input in real time.

? Key Concepts

  • Array state: Store list items in a state variable (e.g., const [todos, setTodos]).
  • Rendering lists: Use map() to convert an array into React elements.
  • Adding items: Create a new array using the spread operator and update state.
  • Removing items: Use filter() to exclude an item and return a new array.
  • Filtering/searching: Use filter() with conditions based on user input.
  • Immutability: Never mutate the original array (avoid methods like push() directly on state).
  • Keys: Always provide a stable key prop when rendering lists.

? Syntax & Theory

At the core of dynamic lists are a few powerful patterns:

  • Rendering: {'items.map(item => <li key={item.id}>{item.name}</li> )'}
  • Adding: setItems([...items, newItem])
  • Removing: setItems(items.filter(item => item.id !== idToRemove))
  • Filtering: const filtered = items.filter(item => item.matchesQuery)

These methods do not modify the original array; instead, they return a new array, which is exactly what React expects when updating state.

? Example: Adding Items to a List

Store the list in state, expose an input box, and update the array whenever the user clicks an Add button.

? View Code Example
// React todo list that lets the user add new tasks dynamically
import React, { useState } from "react";

function TodoList() {
  const [todos, setTodos] = useState(["Learn React", "Build App"]);
  const [input, setInput] = useState("");

  const addTodo = () => {
    if (input.trim() === "") return; // Ignore empty or whitespace-only tasks
    setTodos([...todos, input]); // Create a new array with the new todo appended
    setInput("");
  };

  return (
    <div>
      <h4>My Todo List</h4>
      <input
        type="text"
        value={input}
        onChange={(e) => setInput(e.target.value)}
        placeholder="Add new task"
      />
      <button className="btn btn-primary ms-2" onClick={addTodo}>
        Add
      </button>

      <ul className="mt-3">
        {todos.map((t, index) => (
          <li key={index}>{t}</li>
        ))}
      </ul>
    </div>
  );
}

export default TodoList;

? What This Component Does

  • Initial todos are "Learn React" and "Build App".
  • When the user types a new task and clicks Add, it is appended to the list.
  • Empty values are ignored using input.trim() to keep the list clean.

?️ Example: Removing Items from a List

Use filter() to create a new array that excludes the item to be removed.

? View Code Example
// List where each item has a Remove button that filters it out
function RemovableList() {
  const [items, setItems] = React.useState(["Pen", "Pencil", "Eraser"]);

  const removeItem = (name) => {
    setItems(items.filter((item) => item !== name)); // Keep everything except the clicked item
  };

  return (
    <ul>
      {items.map((item) => (
        <li key={item}>
          {item}
          <button
            className="btn btn-sm btn-danger ms-2"
            onClick={() => removeItem(item)}
          >
            Remove
          </button>
        </li>
      ))}
    </ul>
  );
}

export default RemovableList;

? What This Component Does

  • Renders a list of stationery items: Pen, Pencil, and Eraser.
  • Each item shows a Remove button next to it.
  • When you click Remove, the component filters that item out and re-renders the list.

? Example: Filtering Lists Dynamically

Implement a simple search bar that filters visible items as the user types, without changing the original data.

? View Code Example
// Product search list that filters items based on a search query
function FilterableList() {
  const [search, setSearch] = React.useState("");
  const products = ["Laptop", "Keyboard", "Mouse", "Headphones", "Monitor"];

  const filtered = products.filter((p) =>
    p.toLowerCase().includes(search.toLowerCase()) // Case-insensitive match with the query
  );

  return (
    <div>
      <h4>Product Search</h4>
      <input
        type="text"
        placeholder="Search product..."
        value={search}
        onChange={(e) => setSearch(e.target.value)}
      />

      <ul className="mt-3">
        {filtered.length > 0 ? (
          filtered.map((p) => <li key={p}>{p}</li>)
        ) : (
          <li className="text-muted">No products found</li>
        )}
      </ul>
    </div>
  );
}

export default FilterableList;

? What This Component Does

  • Keeps the original product array unchanged.
  • Derives a filtered array based on the current search text.
  • Shows a helpful message when no items match the filter.

⚙️ Example: Combining Add, Remove & Filter

A realistic list often needs all three behaviours together: adding items, removing items, and filtering them based on a search query.

? View Code Example
// Grocery list that supports adding, removing, and live filtering of items
function SmartList() {
  const [list, setList] = React.useState(["Milk", "Bread", "Butter"]);
  const [query, setQuery] = React.useState("");
  const [input, setInput] = React.useState("");

  const addItem = () => {
    if (input.trim() === "") return; // Prevent adding empty grocery items
    setList([...list, input]);
    setInput("");
  };

  const removeItem = (name) => {
    setList(list.filter((item) => item !== name)); // Remove the clicked item from the list
  };

  const filtered = list.filter((item) =>
    item.toLowerCase().includes(query.toLowerCase())
  );

  return (
    <div>
      <h4>Grocery List</h4>
      <input
        type="text"
        placeholder="Search..."
        value={query}
        onChange={(e) => setQuery(e.target.value)}
      />
      <input
        type="text"
        placeholder="Add item"
        className="ms-2"
        value={input}
        onChange={(e) => setInput(e.target.value)}
      />
      <button className="btn btn-primary ms-2" onClick={addItem}>
        Add
      </button>

      <ul className="mt-3">
        {filtered.map((item) => (
          <li key={item}>
            {item}
            <button
              className="btn btn-sm btn-outline-danger ms-2"
              onClick={() => removeItem(item)}
            >
              Remove
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default SmartList;

? What This Component Does

  • Maintains a grocery list that starts with Milk, Bread, and Butter.
  • Lets the user add new grocery items via the input and Add button.
  • Provides a search box that live-filters the visible items.
  • Shows a Remove button next to each item to delete it from the list.

? Performance & Best Practices

  • Always use a unique, stable key when rendering list items (prefer IDs over indexes).
  • Prefer functional updates like setList(prev => [...prev, input]) when the new value depends on the previous state.
  • Use useMemo() to memoise expensive filtering or sorting on large datasets.
  • Avoid mutating arrays directly (e.g., calling push() on state arrays).
  • Keep state minimal and derive filtered lists from base data instead of duplicating state.

? Tips

  • Use map() to render lists; use filter() for removal and search.
  • Keep arrays immutable by returning a new array on every update.
  • Make searches user-friendly with toLowerCase() for case-insensitive matching.
  • Show a clear, friendly message when no items are available or no results are found.

? Try It Yourself

  1. Create a to-do app where users can add and delete tasks using useState() and map().
  2. Add a search box that filters tasks in real time using filter().
  3. Extend the component to mark items as completed or pending (e.g., using a boolean flag).
  4. Experiment with sorting the list alphabetically using sort() before rendering.

Goal: Learn how to manage dynamic lists in React using map() and filter(), handle additions and deletions, and render filtered data efficiently.