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?
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:
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;
}
}
}
});
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.