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.
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.
JSXimport { 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
- Open your movie-browser project and locate your main list component.
- Ensure you have a
moviesarray passed down as props (following our earlier work on Rendering Lists of Data). - Implement the
filterlogic as shown above. - Add a "No movies found" message if
filteredMovies.lengthis 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 updatefilteredevery timemovieschanges orsearchQuerychanges. 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.
Work with me

React & Next.js Dashboard / Admin UI Development
A clean, data-rich dashboard UI in React or Next.js — charts, tables, and real-time data that your users will actually enjoy using.

Headless WordPress + Next.js Frontend Development
Keep WordPress for content, get a lightning-fast Next.js frontend. The best of both worlds — familiar editing, modern speed.