YouTip LogoYouTip

React Blog Search

In this chapter, you will dive into useEffect's dependency change mechanism to implement real-time search box filtering and debounce optimization. * * * ## useEffect Dependency Change Trigger When a value in useEffect's dependency array changes, React will re-execute the effect. ## Example ```javascript import{ useState, useEffect } from 'react' function SearchDemo(){ const[keyword, setKeyword]= useState('') const[results, setResults]= useState([]) // Whenever keyword changes, re-execute the filter useEffect(()=>{ console.log('keyword changed to:', keyword) // Search logic can be executed here setResults(/* filtered results */) },)// depends on keyword return(
setKeyword(e.target.value)} placeholder="Search..." />

Current search: {keyword}

) } ``` This pattern is suitable for listening to a certain state and automatically executing corresponding operations when it changes. * * * ## Handling in Events vs useEffect There are two ways to implement search filtering: | Method | Implementation | Use Case | | --- | --- | --- | | Event Handler | Direct filtering in onChange | Simple logic, triggered in only one place | | useEffect Response | useEffect depends on keyword | Multiple data sources may affect filtering results | In blog scenarios, the search box input filtering logic is simple, so it's more appropriate to place it directly in event handlers or useMemo. useEffect is more suitable for scenarios that need to synchronize with external systems (such as calling APIs, storing to localStorage). * * * ## Debounce Optimization If search is triggered on every key press (fine for local filtering, but wasteful for network requests), it causes a lot of waste. The idea of Debounce: execute the operation after the user stops inputting for a period of time. ## Example ```javascript import{ useState, useEffect } from 'react' function useDebounce(value, delay =300){ const[debouncedValue, setDebouncedValue]= useState(value) useEffect(()=>{ // Set timer: update debouncedValue after delay ms const timer = setTimeout(()=>{ setDebouncedValue(value) }, delay) // Cleanup function: if value changes again within delay, clear the previous timer return()=> clearTimeout(timer) },[value, delay]) return debouncedValue } // Using debounce function SearchInput(){ const[keyword, setKeyword]= useState('') const debouncedKeyword = useDebounce(keyword,300) // Only execute when the debounced value changes (e.g., send request) useEffect(()=>{ if(debouncedKeyword){ console.log('Actually executing search:', debouncedKeyword) // fetch(`/api/search?q=${debouncedKeyword}`) } },) return( setKeyword(e.target.value)} placeholder="Search..." /> ) } ``` > Debounce principle: each input resets a 300ms timer, only when there's no new input within 300ms will the timer execute and debouncedValue will update. This prevents frequent search triggers when users type quickly. * * * ## Hands-on: Add Real-time Search to the Blog ## Example ```javascript // File path: src/pages/HomePage.jsx import{ useState, useEffect, useMemo } from 'react' import BlogCard from '../components/BlogCard' import CategoryFilter from '../components/CategoryFilter' function HomePage(){ const[articles, setArticles]= useState([]) const[isLoading, setIsLoading]= useState(true) const[error, setError]= useState(null) const[activeCategory, setActiveCategory]= useState('All') const[keyword, setKeyword]= useState('')// Search keyword // Load data useEffect(()=>{ let cancelled =false async function fetchPosts(){ setIsLoading(true) try{ const res = await fetch('/posts.json') const data = await res.json() if(!cancelled) setArticles(data) }catch(err){ if(!cancelled) setError(err.message) }finally{ if(!cancelled) setIsLoading(false) } } fetchPosts() return()=>{ cancelled =true} },[]) const categories = useMemo(()=>{ return['All', ...new Set(articles.map(a => a.category))] },) // Filter + Search: filter by category and keyword simultaneously const filteredArticles = use
← React Blog Context ReducerReact Blog Router β†’