SEB_FE_44/Main_Project
리팩토링 - queries 분리
언젠간코딩잘함
2023. 8. 9. 16:28
리팩토링 - queries 분리
폴더구조, path alias 설정이 끝났으니 무거웠던 컴포넌트들의 코드를 분리시켜 주어야 한다. 폴더구조를 더 개선하기 위해서도 필요하고 성능 향상등 다양한 이유로 아무튼 해야 한다. 우리 프로젝트의 api 는 분리되어 있는 반면에 리액트 쿼리는 그렇지 않기 때문에, 가장 먼저 수정해야겠다고 생각해서 useQuery, useMutation 들을 분리시킬 것이다!
이전 Bookmark 컴포넌트
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { AxiosError } from 'axios';
import { BsHeart, BsHeartFill } from 'react-icons/bs';
import { useNavigate } from 'react-router-dom';
import { GetIsBookmark, PostBookmark } from '@/api/api';
import BookmarkLoading from '@/components/mediaDetail/bookmark/BookmarkLoading';
import { S_IconWrapper } from '@/styles/style';
import useIsLoggedIn from '@/utils/isLoggedIn';
import { notifyError, notifyWithIcon } from '@/utils/notify';
function Bookmark({ contentId }: { contentId: string }) {
const queryClient = useQueryClient();
const isLoggedIn = useIsLoggedIn();
const navigate = useNavigate();
if (!isLoggedIn) {
return (
<S_IconWrapper>
<div>
<BsHeart
color="white"
size="35"
onClick={() => notifyError('로그인 후 이용 가능합니다')}
/>
<p>찜</p>
</div>
</S_IconWrapper>
);
}
const { isLoading, data, isSuccess, error } = useQuery(
['isBookmarked', contentId],
() => GetIsBookmark(contentId),
{
enabled: isLoggedIn,
}
);
const BookmarkMutation = useMutation({
mutationFn: (contentId: string) => PostBookmark(contentId),
onSuccess: () => {
if (!data) {
notifyWithIcon('찜 완료!', '❤️');
} else {
notifyWithIcon('찜 취소..', '🤍');
}
queryClient.invalidateQueries(['isBookmarked', contentId]);
queryClient.invalidateQueries(['userContents']);
},
});
const handleBookmark = () => {
if (!BookmarkMutation.isLoading) {
BookmarkMutation.mutate(contentId);
}
};
if (isLoading) {
return <BookmarkLoading />;
}
if (error instanceof AxiosError) {
if (!error.status && error.code === 'ERR_NETWORK') navigate('/error');
}
if (isSuccess) {
return (
<S_IconWrapper>
<div>
{data ? (
<BsHeartFill
color="white"
size="34"
className="isTrue"
onClick={handleBookmark}
/>
) : (
<BsHeart color="white" size="35" onClick={handleBookmark} />
)}
<p className={data ? 'isTrue' : ''}>찜</p>
</div>
</S_IconWrapper>
);
}
}
export default Bookmark;
지금은 북마크 버튼을 렌더링 해주고, api 요청을 주고받고..
위 코드에서 useQuery 와 useMutation 을 뽑아서 새로운 컴포넌트에 옮겨주고 값만 가져오게 수정하자.
먼저 useIsBookmarkQuery.tsx 컴포넌트를 새로 만들어 주었다.
import { useQuery } from '@tanstack/react-query';
import { GetIsBookmark } from '@/api/api';
const useIsBookmarkQuery = (contentId: string) => {
return useQuery(['isBookmarked', contentId], () => GetIsBookmark(contentId));
};
export default useIsBookmarkQuery;
contentId 만 받아서 똑같이 api 요청을 보내준다.
마찬가지로 useBookmarkMutation.tsx 컴포넌트도 만들어줬다.
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { PostBookmark } from '@/api/api';
import { notifyWithIcon } from '@/utils/notify';
const useBookmarkMutation = (contentId: string, data: boolean) => {
const queryClient = useQueryClient();
const bookmarkMutation = useMutation({
mutationFn: () => PostBookmark(contentId),
onSuccess: () => {
if (!data) {
notifyWithIcon('찜 완료!', '❤️');
} else {
notifyWithIcon('찜 취소..', '🤍');
}
queryClient.invalidateQueries(['isBookmarked', contentId]);
queryClient.invalidateQueries(['userContents']);
},
});
return bookmarkMutation;
};
export default useBookmarkMutation;
이후 Bookmark 컴포넌트
import { AxiosError } from 'axios';
import { BsHeart, BsHeartFill } from 'react-icons/bs';
import { useNavigate } from 'react-router-dom';
import BookmarkLoading from '@/components/mediaDetail/bookmark/BookmarkLoading';
import useBookmarkMutation from '@/queries/mediaDetail/useBookmarkMutation';
import useIsBookmarkQuery from '@/queries/mediaDetail/useIsBookmarkQuery';
import { S_IconWrapper } from '@/styles/style';
import useIsLoggedIn from '@/utils/isLoggedIn';
import { notifyError } from '@/utils/notify';
function Bookmark({ contentId }: { contentId: string }) {
const isLoggedIn = useIsLoggedIn();
const navigate = useNavigate();
if (!isLoggedIn) {
return (
<S_IconWrapper>
<div>
<BsHeart
color="white"
size="35"
onClick={() => notifyError('로그인 후 이용 가능합니다')}
/>
<p>찜</p>
</div>
</S_IconWrapper>
);
}
const { isLoading, data, isSuccess, error } = useIsBookmarkQuery(contentId);
const bookmarkMutation = useBookmarkMutation(contentId, data);
const handleBookmark = () => {
if (!bookmarkMutation.isLoading) {
bookmarkMutation.mutate();
}
};
if (isLoading) {
return <BookmarkLoading />;
}
if (error instanceof AxiosError) {
navigate('/error');
}
if (isSuccess) {
return (
<S_IconWrapper>
<div>
{data ? (
<BsHeartFill
color="white"
size="34"
className="isTrue"
onClick={handleBookmark}
/>
) : (
<BsHeart color="white" size="35" onClick={handleBookmark} />
)}
<p className={data ? 'isTrue' : ''}>찜</p>
</div>
</S_IconWrapper>
);
}
}
export default Bookmark;
20줄도 안 줄은 것 같은데 아무튼 만족스럽다. 이런 식으로 다른 파일들도 리액트 쿼리를 분리해야지..