如何实现筛选结果自动更新博客文章列表?
博客搜索+无限滚动问题的解决方案
问题根源
提交搜索表单后,URL的筛选参数filter已更新,但组件没有自动触发新的搜索流程——现有帖子列表保留着旧数据,分页、加载状态也未重置,必须手动刷新才能加载符合新条件的内容。
具体解决步骤
1. 监听筛选参数变化,重置状态并加载初始数据
添加一个useEffect,当filter(从URL的searchParams获取)变化时,重置所有和数据、分页相关的状态,并发起第一页的搜索请求:
useEffect(() => { // 重置状态:清空现有帖子、回到第0页、恢复加载更多的开关 setPosts([]); setPage(0); setMorePosts(true); // 请求新筛选条件下的第一页数据 fetchPosts(`http://localhost:4000/blog?skip=0&limit=1&q=${filter || ''}`); }, [filter]); // 仅当filter变化时触发
2. 优化搜索提交逻辑(可选)
原代码中submissionHandler里的e.target.reset()属于重复操作(已经通过setSearchField('')清空了输入框),可以去掉:
const submissionHandler = (e) => { e.preventDefault(); setSearchParams({ filter: searchField }); setSearchField(''); };
3. 精简Intersection Observer的依赖项
原useEffect依赖了posts,会导致每次帖子更新都重建观察者,实际上只需要依赖filter和morePosts即可,避免不必要的性能消耗:
useEffect(()=>{ const observer = new IntersectionObserver(onIntersect) if (elementRef.current){ observer.observe(elementRef.current) } return ()=>{ observer.disconnect() } },[filter, morePosts])
修改后的完整组件代码
export default function Posts (){ const {title} = useParams() const [searchParams,setSearchParams] = useSearchParams() const [posts,setPosts] = useState([]) const [morePosts ,setMorePosts] =useState(true) const [page,setPage ]= useState(0) const elementRef = useRef(null) const filter = searchParams.get('filter') const [searchField,setSearchField] = useState('') const onSearchChange=(e)=>{ setSearchField(e.target.value) } const submissionHandler =(e)=>{ e.preventDefault() setSearchParams({filter:searchField}) setSearchField('') } const onIntersect=(entries)=>{ if(entries[0].isIntersecting && morePosts ){ fetchPosts(`http://localhost:4000/blog?skip=${page}&limit=1&q=${filter?filter:''}`) } } function fetchPosts(url){ fetch(url,{ method:'get', mode:'cors', }) .then(response=>response.json()) .then(data=>{ if (data.posts.length === 0){ setMorePosts(false) } else if(data.success){ setPosts(p=>[...p,...data.posts]) setPage(prev=>prev+1) } }) } // 新增:监听filter变化,重置状态并加载初始数据 useEffect(() => { setPosts([]); setPage(0); setMorePosts(true); fetchPosts(`http://localhost:4000/blog?skip=0&limit=1&q=${filter || ''}`); }, [filter]); // 优化:调整观察者依赖项 useEffect(()=>{ const observer = new IntersectionObserver(onIntersect) if (elementRef.current){ observer.observe(elementRef.current) } return ()=>{ observer.disconnect() } },[filter, morePosts]) return( <> <FormComponent style={{width:'20rem',alignSelf:'center',marginBottom:'10pt'}} onSubmit={submissionHandler} > <input type='text' placeholder='Search Posts' value={searchField} onChange={e=>onSearchChange(e)}/> </FormComponent> {posts.map((post,i)=>{ const publishedDate = new Date(post.published_at) const options = { year: 'numeric', month: 'short', day: 'numeric' } const postDate = publishedDate.toLocaleDateString('en-us',options) return ( <BlogCard key={i+post.title} id={i} cardImage={post.post_img} slug={post.slug} title={post.title} author={post.author} body={post.body} date={postDate} tags={ post.tags.map((tag,i)=>{ return <span style={{cursor:'pointer'}} key={i} > {tag} </span> }) } categories={ post.categories.map((cat,i)=>{ return <span style={{cursor:'pointer'}} key={i} > {cat} </span> }) } /> ) })} {morePosts && <div ref={elementRef}>...Load More Posts</div>} </> ) }
内容的提问来源于stack exchange,提问作者Nineisten
相关产品推荐
相关产品推荐

