Skip to content

Commit 433648c

Browse files
committed
refactor: 게시글 좋아요 & 취소 api도 react-query를 사용해 구현
1 parent 6113031 commit 433648c

1 file changed

Lines changed: 33 additions & 54 deletions

File tree

src/pages/Post/PostBase/index.tsx

Lines changed: 33 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import { useEffect, useState, useRef } from 'react';
22
import { useNavigate, useParams } from 'react-router-dom';
33

4-
import dayjs from 'dayjs';
5-
import { useRecoilState } from 'recoil';
6-
import 'dayjs/locale/ko';
4+
import { useMutation, useQueryClient } from '@tanstack/react-query';
5+
import dayjs, { extend } from 'dayjs';
6+
import relativeTime from 'dayjs/plugin/relativeTime';
77

88
import theme from '@styles/theme';
99

10-
import { getPostDetailApi } from '@apis/post';
10+
import { usePostDetail } from '@apis/post';
1111
import { togglePostLikeStatusApi } from '@apis/post-like';
12-
import { postIdAtom, userAtom, isPostRepresentativeAtom } from '@recoil/Post/PostAtom';
1312

1413
import Left from '@assets/arrow/left.svg';
1514
import Message from '@assets/default/message.svg';
@@ -51,11 +50,7 @@ import {
5150
} from './styles';
5251

5352
const PostBase: React.FC<PostBaseProps> = ({ onClickMenu }) => {
54-
const [, setPostId] = useRecoilState(postIdAtom);
55-
const [post, setPost] = useState<GetPostDetailResponse['data']>();
56-
const [user, setUser] = useRecoilState(userAtom);
57-
const [, setIsPostRepresentative] = useRecoilState(isPostRepresentativeAtom);
58-
const [timeAgo, setTimeAgo] = useState<string | null>();
53+
extend(relativeTime);
5954
const [isTextOverflowing, setIsTextOverflowing] = useState(false);
6055
const [showFullText, setShowFullText] = useState(false);
6156
const [isLikeCommentBottomSheetOpen, setIsLikeCommentBottomSheetOpen] = useState(false);
@@ -64,6 +59,12 @@ const PostBase: React.FC<PostBaseProps> = ({ onClickMenu }) => {
6459
const { postId } = useParams<{ postId: string }>();
6560
const contentRef = useRef<HTMLDivElement>(null);
6661

62+
const { data } = usePostDetail(Number(postId));
63+
const queryClient = useQueryClient();
64+
const post = data?.data;
65+
const user = post?.user;
66+
const timeAgo = dayjs(post?.createdAt).locale('ko').fromNow();
67+
6768
const nav = useNavigate();
6869

6970
const handleLikeCommentOpen = (tab: 'likes' | 'comments') => {
@@ -80,48 +81,26 @@ const PostBase: React.FC<PostBaseProps> = ({ onClickMenu }) => {
8081
};
8182

8283
// 게시글 좋아요 누르기/취소하기 api
83-
const togglePostLikeStatus = async () => {
84-
if (!post || !postId) return;
85-
86-
const prevPost = { ...post }; // 현재 상태 저장
87-
setPost({
88-
...post,
89-
isPostLike: !post.isPostLike,
90-
postLikesCount: post.isPostLike ? post.postLikesCount - 1 : post.postLikesCount + 1,
91-
}); //사용자가 좋아요를 누르면 먼저 클라이언트에서 post 상태를 변경(낙관적 업데이트)
92-
93-
try {
94-
const response = await togglePostLikeStatusApi(Number(postId));
95-
setPost({
96-
...post,
97-
isPostLike: response.data.isPostLike,
98-
postLikesCount: response.data.postLikesCount,
99-
}); // 서버로 요청 후 성공하면 그대로 유지
100-
} catch (error) {
101-
console.error('Error toggling like status:', error);
102-
setPost(prevPost); // 실패하면 원래 상태로 롤백
103-
}
104-
};
105-
106-
useEffect(() => {
107-
setPostId(Number(postId));
108-
109-
// 게시글 정보 가져오기
110-
const getPost = async () => {
111-
try {
112-
const response = await getPostDetailApi(Number(postId));
113-
const data = response.data;
114-
setPost(data);
115-
setUser(data.user);
116-
setIsPostRepresentative(data.isRepresentative);
117-
setTimeAgo(dayjs(data.createdAt).locale('ko').fromNow());
118-
} catch (error) {
119-
console.error('Error fetching post data:', error);
120-
}
121-
};
122-
123-
getPost();
124-
}, [postId]);
84+
const { mutate: togglePostLikeStatus } = useMutation({
85+
mutationFn: () => togglePostLikeStatusApi(Number(postId)),
86+
onSuccess: () => {
87+
queryClient.setQueryData(['postDetail', Number(postId)], (oldData: GetPostDetailResponse | undefined) => {
88+
if (!oldData) return oldData;
89+
90+
const newData = {
91+
...oldData,
92+
data: {
93+
...oldData.data,
94+
postLikesCount: oldData.data.postLikesCount + (oldData.data.isPostLike ? -1 : 1), // 기존 좋아요 개수를 토대로 증가/감소
95+
isPostLike: !oldData.data.isPostLike, // 좋아요 상태 변경
96+
},
97+
};
98+
console.log('newData', newData);
99+
100+
return newData;
101+
});
102+
},
103+
});
125104

126105
useEffect(() => {
127106
if (contentRef.current) {
@@ -160,7 +139,7 @@ const PostBase: React.FC<PostBaseProps> = ({ onClickMenu }) => {
160139
$textTheme={{ style: 'body2-medium' }}
161140
color={theme.colors.text.primary}
162141
>
163-
{user.nickname}
142+
{user?.nickname ?? '알수없음'}
164143
</UserName>
165144
<StyledText
166145
className="timeAgo"
@@ -186,7 +165,7 @@ const PostBase: React.FC<PostBaseProps> = ({ onClickMenu }) => {
186165

187166
<IconRow>
188167
<IconWrapper>
189-
<Icon onClick={togglePostLikeStatus}>
168+
<Icon onClick={() => togglePostLikeStatus()}>
190169
{post?.isPostLike ? <Like isFilled={true} color={theme.colors.brand.primary} /> : <Like />}
191170
</Icon>
192171
<span onClick={() => handleLikeCommentOpen('likes')}>{post?.postLikesCount ?? 0}</span>

0 commit comments

Comments
 (0)