Home > Software design >  Component is updating state, but not forcing a re-render - instead, it is adding to state and just a
Component is updating state, but not forcing a re-render - instead, it is adding to state and just a

Time:06-21

Edited to show slice*

I am a student, and I am making a Reddit type site using Reddit's JSON API. Like Reddit, the main screen shows the feed, and I have a list of subreddits on the side. When you click on one of those subreddits, the main feed needs to show the feed for that particular subreddit. The API call works just fine and my route params seem to work just fine. However, while useEffect is noticing that the url is changing and makes the fetch request to get the appropriate data, the component doesn't re-render. Instead, it just adds the new data to the previous state. So, for example, if I click on the "home" link, the feed displays the correct "home" data...but then if I click on another subreddit (like funny animals), it keeps the home feed and adds the "funny animals" to the end of the home feed. The state never refreshes, it just grows.

I have forced a complete refresh (using tags instead of tags in the subreddit list where I pass the params), and everything works as intended...but of course, I'd rather deal with the change within React.

I am required to use Redux Toolkit for this project, so maybe it's an issue with how I'm interacting with the store?

I have read through documentation and have looked around online, but I am just not entirely sure what I should be looking for anymore since I seem to have hit dead ends. Some of it is a bit

This has frustrated me for a couple of days now, so I would appreciate any help!!

Here is the code:

export default function SubReddit() {
    const [loading, setIsLoading] = useState(false)
    const dispatch = useDispatch()

    const { name } = useParams()
    let url = 'https://www.reddit.com/r/'   name   '.json'

    const posts = useSelector(selectPosts)
    // const { loading } = useSetData(url)

    const postData = async () => {
        setIsLoading(true)

        try {
            const response = await fetch(url);

            if (response.status === 200) {
                const jsonResponse = await response.json();

                console.log(jsonResponse)
                const newData = jsonResponse.data.children

                //create new object to be stored in Redux and dispatch to store

                newData.map((item) => {
                    dispatch(setData({
                        id: item.data.id,
                        title: item.data.title,
                        author: item.data.author,
                        comments: item.data.num_comments,
                        subreddit: item.data.subreddit_name_prefixed,
                        url: item.data.url,
                        text: item.data.selftext,
                        media: item.data.media,
                        img: (typeof (item.data.preview) !== 'undefined') ? item.data.preview.images[0].source.url.replace("amp;", "") : null

                    }))

                })

                setIsLoading(false)
            }

        } catch (error) {
            console.log(error)
            setIsLoading(false)
        } finally {
        setIsLoading(false);
      }
    }
    
useEffect (() => {
    postData()
}, [url])

return (
    <div className="feed-container">

        {posts.map(post => (
            <FeedCard key={post.id} image={post.image} title={post.title} url={post.url} media={post.media} text={post.text} author={post.author} comments={post.comments} />
        ))}
    </div>
)
}

Here is the slice:

import { createSlice } from "@reduxjs/toolkit";

const initialState = {posts:[]}
export const dataSlice = createSlice({
    name: 'posts',
    initialState,
    reducers: {
        setData: (state, action) => {

            // console.log(action.payload)

            state.posts.push({
                id: action.payload.id,
                title: action.payload.title,
                author: action.payload.author,
                comments: action.payload.comments,
                subreddit: action.payload.subreddit,
                url: action.payload.url,
                text: action.payload.text,
                image: action.payload.img,
                media: action.payload.media

            })

        },


    }

}
)

export default dataSlice.reducer;

export const { setData } = dataSlice.actions;

export const selectPosts = state => state.data.posts;
 

CodePudding user response:

Your reducer is working as you expect. So what you need is a resetState reducer to reset the state of your store before you call the postData() function in your useEffect hook. Rerendering of the component is done successfully since you were able to see the posts grow.

More information here: https://bionicjulia.com/blog/clear-redux-toolkit-state-with-redux-persist-and-typescript

  • Related