Back to Blog
Lesson 18 of the React Fundamentals: Build Modern UIs from Scratch course
ReactJune 25, 20263 min read

Filtering the Movie List: Real-Time Search in React

Master real-time filtering in React by synchronizing your search state with your data. Learn to derive UI state efficiently without redundant variables.

Reactstate managementfilteringreal-time searchUI developmentjavascriptfrontend

Previously in this course, we covered Managing State with useState: A Beginner’s Guide to React Hooks to track individual variables and Building an Interactive Search Bar to capture user input. Now, we will connect those pieces to implement filtering, allowing your users to find specific movies in real-time as they type.

Understanding Derived State for Filtering

In React, a common trap is trying to keep "everything" in state. You might be tempted to create a filteredMovies state variable and update it whenever the user types.

Don't do this.

Instead, we use derived state. Since we already have the full list of movies (from props or initial state) and the current search query (from our controlled input), we can calculate the filtered list during the render. This ensures your UI is always perfectly in sync with the underlying data.

Worked Example: Filtering Movie Data

Let's look at how to implement this in our movie-browser project. We will take our master list of movies and apply a .filter() method before mapping over them to display the cards.

JSX
import { useState } from CE9178">'react';
import MovieCard from CE9178">'./MovieCard';

const MovieList = ({ movies }) => {
  const [searchQuery, setSearchQuery] = useState("");

  // Derived state: calculate this on every render
  const filteredMovies = movies.filter((movie) =>
    movie.title.toLowerCase().includes(searchQuery.toLowerCase())
  );

  return (
    <div>
      <input
        type="text"
        placeholder="Search movies..."
        value={searchQuery}
        onChange={(e) => setSearchQuery(e.target.value)}
      />
      
      <div className="movie-grid">
        {filteredMovies.map((movie) => (
          <MovieCard key={movie.id} movie={movie} />
        ))}
      </div>
    </div>
  );
};

In this snippet, filteredMovies is not a state variable. It is a plain JavaScript variable calculated based on the current searchQuery. When the user types, setSearchQuery triggers a re-render, React runs this logic again, and the list updates instantly.

Hands-on Exercise

  1. Open your movie-browser project and locate your main list component.
  2. Ensure you have a movies array passed down as props (following our earlier work on Rendering Lists of Data).
  3. Implement the filter logic as shown above.
  4. Add a "No movies found" message if filteredMovies.length is zero, using the concepts from Conditional Rendering.

Common Pitfalls

  • Storing Filtered Results in State: Avoid const [filtered, setFiltered] = useState(movies). This leads to "state synchronization hell," where you have to manually update filtered every time movies changes or searchQuery changes. Always calculate it on the fly.
  • Case Sensitivity: Users expect "matrix" to find "The Matrix." Always use .toLowerCase() on both the search query and the movie title to ensure your search is case-insensitive.
  • Performance at Scale: For thousands of items, filtering on every keystroke can become expensive. However, for a typical movie list (hundreds of items), this approach is perfectly performant. If you eventually need to optimize, look into techniques like debouncing, which we will cover later in the course.

Recap

Real-time search is fundamentally a task of state synchronization. By keeping the search input as the "source of truth" and deriving the display list from it, you minimize bugs and make your code significantly easier to reason about. Remember: if a value can be computed from existing state, do not store it in a separate useState hook.

Up next: We'll move beyond simple input handling to Handling Form Submissions to manage more complex user interactions.

Similar Posts