Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React button not rerendering the component

I am making a blog with React and Sanity, and am trying to use buttons to allow the user to sort blog posts by tag (category). Currently, the sorting works fine if I hard code the tag I want to sort the posts by, but I want to be able to use buttons to change the sort tag. Right now the button is able to change text on the screen to the correct category, but It does not update the visible posts (does not actually sort them).

Here is my code for the blog page:

import React from "react";
import { useState, useEffect } from "react"

import Footer from "../Footer";
import Header from "./Header";

import client from "../../client"
import BlockContent from "@sanity/block-content-to-react";

import { Link } from "react-router-dom";

const Blog = () =>
{
    const [posts, setPosts] = useState([])
    const [sort, setSort] = useState("all")
    
    useEffect(() => {
        client.fetch(
            //This line sorts posts by the value of 'keyword' 
            `*[_type == "post" && $keyword in tags] { 
                title,
                slug,
                body,
                mainImage {
                    asset -> {
                        _id,
                        url
                    },
                    alt
                },
                tags,
                publishedAt
            }`,{"keyword":sort} //This line sets the value of 'keyword' to the value of 'sort'
        )
        .then((data) => setPosts(data))
        .catch(console.error)
    }, [])

    //This function prints the tag that was clicked to the console and updates the 
    //value of 'sort'. It is supposed to rerender the component to display only the
    //posts associated with the tag clicked, but it does not.
    function sortPosts(e) {
        console.log(e)
        setSort(e)
    }

    return (
        <div className = "bg-gray-100 dark:bg-zinc-900">
            <Header />
            <div className = "" >
                <p className = "title pt-32">Welcome to My Blog!</p>

                //This line correctly displays the tag that is supposed to determine which posts to display
                <p className = "text-center font-semibold">Currently showing: {sort} posts</p>

                <div className = "flex items-center justify-center mt-16">
                    <div className = "grid grid-cols-1 xl:grid-cols-3 lg:grid-cols-2 md:grid-cols-1 gap-10 mx-16">
                    {posts.map((post) => (
                        <article key={post.slug.current} className = "rounded-xl max-w-sm bg-white dark:bg-zinc-950 shadow-xl dark:shadow-gray-100/10">
                            <img src={post.mainImage.asset.url} alt={post.title} className = "object-fill object-center rounded-t-xl" />
                            <div className = "p-6">
                                <p className = "text-2xl font-semibold mb-3 dark:text-gray-100">{post.title}</p>
                                {post.tags.map((tags, key) => (
                                    <div className = "inline-block">

                                        //This line displays a button for each tag associated with the current post and calls the sortPosts function
                                        <button key = {key} onClick={() => sortPosts(tags)} className = "px-2 inline-flex mb-2 mr-2 rounded-2xl hover:bg-white bg-gray-100 dark:hover:bg-zinc-950 dark:bg-zinc-800 dark:text-white duration-300 transition-colors cursor-pointer">{tags}</button>

                                    </div>
                                ))}
                                <div class = "preview">
                                    <BlockContent blocks={post.body} projectId="2hp9gld0" dataset="production" />
                                </div>
                                <button className="button-main items-center mt-2 dark:text-gray-100 block">
                                    <Link to = {`/blog/${post.slug.current}`} className = "">Read Full Article</Link>
                                </button>
                            </div>
                        </article>
                    ))}
                    </div>
                </div>
            </div>
            <div className = "pb-10 bg-gray-100 dark:bg-zinc-900">
                <Footer />
            </div>
        </div>
    )
}

export default Blog;

As I said, this code works perfectly fine other than actually rerendering the correct posts when a button is clicked to sort by a specific tag. Any help is appreciated!

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

If you fetch data and setPosts in useEffect, You should add sort state to useEffect dependency, to update the posts when you change the sort state value by setSort.
like below:

    const [posts, setPosts] = useState([])
    const [sort, setSort] = useState("all")
    
    useEffect(() => {
        client.fetch(
            //This line sorts posts by the value of 'keyword' 
            ...
        .then((data) => setPosts(data))
        .catch(console.error)
    }, [sort])
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading