Dont understand how to see likes on posts without refreshing the page. Sending the request to backend and receiving the response seems fine, posts getting liked and unliked, but to see the likes i need to reload the page and im having a hard time understanding what to do now. Still learning how everything works.
here is the backend code
async likePost(req, res) {
try {
const post = await Post.findOne({ where: { id: req.params.id } });
const alreadyLiked = await Likes.findOne({ where: { post_id: post.id, user_id: req.session.user.id } });
if (!alreadyLiked) {
const like = await Likes.create({ post_id: post.id, user_id: req.session.user.id });
console.log('post liked');
res.json({ like });
} else {
await Likes.destroy({ where: { post_id: post.id, user_id: req.session.user.id } });
console.log('post unliked');
res.sendStatus(200);
}
} catch (error) {
console.log(error);
res.sendStatus(500).send('Server Error');
}
}
here is the likeSlice
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"
import axios from "axios";
const initialState = {
likes: []
}
export const upvotePost = createAsyncThunk(
'likes/upvotePost',
async (id, { rejectWithValue, dispatch }) => {
try {
const response = await axios.post(`/posts/${id}/likes`);
dispatch(addLike(response.data.like))
} catch (error) {
rejectWithValue(error.message);
}
}
)
export const likeSlice = createSlice({
name: 'likes',
initialState,
reducers: {
addLike: (state, action) => {
state.likes.push(action.payload);
}
}
})
const { addLike } = likeSlice.actions;
export default likeSlice.reducer;
here is the post code
const OnePost = () => {
const post = useSelector(state => state.post.post_id);
const user = useSelector(state => state.auth.user);
console.log('post', post);
const { id } = useParams();
const dispatch = useDispatch();
const num = post.likedBy?.length
console.log('num', num);
const [like, setLike] = useState(num)
console.log('like--->', like);
useEffect(() => {
dispatch(getOnePost(id))
}, [like])
const navigate = useNavigate();
const openUserPageHandler = () => {
dispatch(getOneUser(post.user_id))
}
const likePostHandler = () => {
// if (post.likedBy?.map(el => el.Likes.user_id == user.id)) {
// setLike(prev => prev - 1)
dispatch(upvotePost(id))
// } else {
// setLike(prev => prev + 1)
// dispatch(upvotePost(id))
// }
}
const avatar = `http://localhost:3001${post.userAvatar}`
const createdAt = new Date(post.createdAt).toLocaleString(undefined, { day: 'numeric', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit' });
const comments = useSelector(state => state.comment.comments);
useEffect(() => {
dispatch(getPostComments(id));
}, [])
return (
<>
<div className='one-post__container'>
<div className='one-post'>
<div className='one-post__info'>
<div className='one-post__info__head'>
<div onClick={() => navigate(-1)}>
<ArrowBackIcon className='one-post__back__arrow' />
</div>
<span className='profile__name'>
<h3>Tweet</h3>
</span>
</div>
<div className='one-post__info__mid'>
<Link to={`/user/${post.userId}`} className='one-post__link'>
<div className='one-post__name' onClick={openUserPageHandler}>
<img src={post.userAvatar ? avatar : default_avatar} alt='' className='one-post__profile__avatar' />
<h4 className='one-post__user__name'>{post.userName}</h4>
</div>
</Link>
<div className='one-post__options'>
<MoreHoriz />
</div>
</div>
<div className='one-post__body'>{post.text}</div>
<div className='one-post__footer'>
<div className='one-post__time'>{createdAt}</div>
<div className='one-post__icons'>
<div className='one-post__icons__options'>
<ChatBubbleOutline fontSize='small' />
</div>
<div className='one-post__icons__options'>
<FavoriteBorderOutlined fontSize='small' onClick={likePostHandler} />
{like > 0 ? like : null}
</div>
</div>
</div>
</div>
</div>
</div>
</>
)
}
and here is how the post looks like
post in console
best i could try was putting likedBy array.length in useState but it was always undefined, and if it managed to appear for some reason it was not working properly
3
Answers
got it working 95% of the time
other 5% my like goes beyond and adds or removes an extra like or two (if i keep clicking) until it stops and thinks for a second and then goes back to correct value
If you want to create a performant social network, you can follow a common approach used by many platforms. When a user performs an action, such as liking a post, you can send a request to the backend and use React.useState to update the value of liked show and add some style if you want. This way, the user who performed the action will be notified about their action. Additionally, when another user logs in, they will be able to see the likes made by other users because the updated data is fetched. Twitter implements this behavior effectively.
there is another approach, Socket.io can be utilized to send real-time updates to users when another user performs an action, such as liking a post. When a user likes a post, you can send an event via Socket.io to the server, which will then broadcast this information to all other connected users. As a result, other users will receive this real-time update and be able to see the actions performed by other users without needing to refresh the page.
check the documentation of socket.io
As stated above, use api calls together with useState. Here’s an example with useMutation (from Tanstack Query (react query)):
And "like" button can be like this: