Back to BlogsReact

React Derived State: Filter a List Without an Extra Effect

Anuj Singh (Admin) 14 September 2026 10 views

If a value can be calculated from current props and state during rendering, storing another copy in state often creates synchronization work. A filtered list is a common example. You need state for the search input, but the matching rows can usually be derived directly from that input and the source list.

Store the user input, derive the result

This component treats courses as the source of truth and query as the editable state. It normalizes the comparison without changing the original course titles. Every render computes the visible rows from the current inputs, so a new courses prop does not need a separate synchronization effect.

import { useState } from "react";

export default function CourseSearch({ courses }) {
  const [query, setQuery] = useState("");
  const normalized = query.trim().toLowerCase();
  const visible = courses.filter(course =>
    course.title.toLowerCase().includes(normalized)
  );
  return (
    <section>
      <label htmlFor="course-search">Find a course</label>
      <input id="course-search" value={query}
        onChange={event => setQuery(event.target.value)} />
      <p>{visible.length} matching courses</p>
      <ul>{visible.map(course =>
        <li key={course.id}>{course.title}</li>
      )}</ul>
    </section>
  );
}

Why an extra effect can be awkward

A pattern that stores filteredCourses and updates it in an effect introduces another value that must remain consistent. The component first renders, then the effect runs and triggers another update. It is easier to forget a dependency or display a briefly stale result. Direct derivation avoids that redundant state.

Memoization is an optimization, not a correction

For a genuinely expensive calculation, useMemo can reuse a result until its dependencies change. Measure before adding it to a small filter. It does not fix a mutated source array or an incorrect filter rule, and correctness should not depend on the cache surviving forever.

Use stable keys and preserve the source list

Use a stable course identifier as the key rather than the displayed index. Do not sort or splice the incoming courses array in place. If sorting is part of the derived view, work on a copy so other consumers do not observe an unexpected mutation.

Practice and check your understanding

Add a beginner-only checkbox and derive the visible rows from both controls. Test an empty query, mixed-case titles and a parent update that replaces the course list. Do not introduce separate state for the filtered result.

Continue learning

Explore the related Code Hacker course syllabus for structured learning. Then read Prevent Stale Search Results with AbortController to connect this exercise to the next skill.

Reference

React: You Might Not Need an Effect provides the underlying API or technical guidance. Check the documentation for the version you use; examples here are small learning exercises rather than complete production implementations.

Found an issue with this guide? Send a correction with the article URL and your example. About our learning material.

Topics in this article

  • react
  • state
  • useeffect
  • derived data

Want to Learn This Practically?

Subscribe to Code Hacker and get hands-on access to 40+ premium courses — Ethical Hacking, Kali Linux, Metasploit, Network Hacking, Bug Bounty & more!