0

Component:

const postState = useSelector((state: RootState) => state.postsSlice.posts);

{
  postState?.map((post) => {
    return (
      <PostCard
        key={post.id}
        title={post.title}
        description={post.body}
        user={post.user}
        voteCount={post.upvotes - post.downvotes}
        onClick={() => navigate(`/posts/${subredditId}/post/${post.id}`)}
      />
    );
  });
}

I am working on a reddit clone project with react typescript. I take the data from the api as an array of objects of the type:

export type Posts = Post[];

export type Post = {
  id: string;
  title: string;
  user: string;
  body: string;
  upvotes: number;
  downvotes: number;
};

And then I store the data in redux toolkit like this:

type PostsArray = {
  posts: Array<Post>;
};

const initialState: PostsArray = { posts: [] };

const PostsSlice = createSlice({
  name: "PostsSlice",
  initialState: initialState,
  reducers: {
    setPostsData(state, action: PayloadAction<Array<Post>>) {
      state.posts = action.payload;
    },
  },
});
export const { setPostsData } = PostsSlice.actions;
export default PostsSlice.reducer;

when I map the objects in my component I show the reddit vote count by subtracting downvotes from upvotes. What I want to do is being able to upvote and downvote different posts and store that vote in redux. I thought about a dispatch that increase the upvotes and a dispatch that increase the downvotes. But I cant figure it out how to do it. I dont know how to acces the upvotes of a specific post in redux. Any ideas?

1 Answer 1

1

For such case you can add a reducer that gets the post id and updates it with the value passed on the action payload, like so:

Reducer

const PostSlice = createSlice({
  name: "PostSlice",
  initialState: initialState,
  reducers: {
    setPostsData(state, action: PayloadAction<Array<Post>>) {
      state.posts = action.payload;
    },
    // reducer to change the vote count
    updateVoteCount(
      state,
      // in the vote payload you can use an enumerate 
     // if you want to avoid typos
      action: PayloadAction<{ id: string; vote: string }>
    ) {
      // find the post by id
      const post = state.posts.find((post) => post.id === action.payload.id);
      if (!post) return;
      if (action.payload.vote === "up") {
        // update the vote depending on payload vote parameter
        post.upvotes += 1;
      }
      if (action.payload.vote === "down") {
        post.downvotes += 1;
      }
    }
  }
});

PostCard

As you didn't provide the code of your PostCard I make a bare example just to show to you:

const PostCard = (props: PostCardProps) => {
  const dispatch = useDispatch();
  return (
    <div>
      <h2>{props.title}</h2>
      <p>{props.description}</p>
      <p>{props.user}</p>
      <p>{props.voteCount}</p>
      <div>
        <button
          onClick={() =>
            //Dispatch the action with vote "up"
            dispatch(updateVoteCount({ id: props.id, vote: "up" }))
          }
        >
          Up vote
        </button>
        <button
          onClick={() =>
            // dispatch with vote "down"
            dispatch(updateVoteCount({ id: props.id, vote: "down" }))
          }
        >
          Down vote
        </button>
      </div>
    </div>
  );
};
export default PostCard;

Please, check the working example.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.