11import { useEffect , useState , useRef } from 'react' ;
22import { 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
88import theme from '@styles/theme' ;
99
10- import { getPostDetailApi } from '@apis/post' ;
10+ import { usePostDetail } from '@apis/post' ;
1111import { togglePostLikeStatusApi } from '@apis/post-like' ;
12- import { postIdAtom , userAtom , isPostRepresentativeAtom } from '@recoil/Post/PostAtom' ;
1312
1413import Left from '@assets/arrow/left.svg' ;
1514import Message from '@assets/default/message.svg' ;
@@ -51,11 +50,7 @@ import {
5150} from './styles' ;
5251
5352const 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