javascriptreactjssearchblogsintersection-observer

How do I update blog post list with filtered results?


Running into an issue with my blog search function. When I submit the search form, the filters/params are updated but in order for the requested blog posts to be returned I have to manually refresh the page. Any ideas on how to approach this properly? Also it should be noted that I have an intersection observer in place for infinite scrolling functionality.


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)
    }
    //handle search 
    const submissionHandler =(e)=>{
        e.preventDefault()
        e.target.reset()
        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)
                }
            })
    }

    useEffect(()=>{
        const observer = new IntersectionObserver(onIntersect)
        if (observer && elementRef.current){
            observer.observe(elementRef.current)
        }
        return ()=>{
            if(observer){
                observer.disconnect()
            }
        }
    },[posts,filter])
    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>}
        </>
    )
}

Solution

  • When the submissionHandler is run, it failed to empty the "posts" array,along with setting the "morePosts" value to true and "page" value to 0. also it needs to be reset when navigating back to the blog route.

    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 location = useLocation()
        
        // create helper function to delete all posts 
        const resetPostlist =()=>{
            setPosts([])
            setMorePosts(true)
            setPage(0)
        }
    
        const onSearchChange=(e)=>{
            setSearchField(e.target.value)
        }
        const submissionHandler =(e)=>{
            e.preventDefault()
            e.target.reset()
            resetPostlist() //placed the reset function here 
            setSearchParams({filter:searchField})
            setSearchField('')
        }
        //resets to default posts when user navigates to blog
        useEffect(()=>{
            if (location.pathname === '/blog'){
                resetPostlist()
            }
        },[location])
        
        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)
                    }
                })
        }
        useEffect(()=>{
            const observer = new IntersectionObserver(onIntersect)
            if (observer && elementRef.current){
                observer.observe(elementRef.current)
            }
            return ()=>{
                if(observer){
                    observer.disconnect()
                }
            }
        },[posts,filter])
        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>}
            </>
        )
    }