DB는 supabase를 사용하기 때문에
일단 bookmark 테이블에 데이터를 넣고 빼는 함수부터 만들었다
// 북마크 추가
export const insertBookmark = async ({ userId, placeId }: Props) => {
const { data, error } = await supabase
.from('bookmarks')
.insert({ user_id: userId, place_id: placeId })
.select();
if (error) {
throw error;
}
return data;
};
// 북마크 삭제
export const deleteBookmark = async ({ userId, placeId }: Props) => {
const { error } = await supabase
.from('bookmarks')
.delete()
.eq('user_id', userId)
.eq('place_id', placeId);
if (error) {
console.log(error);
}
};
// 북마크 가져오기
export const getBookmark = async ({ userId, placeId }: Props) => {
const { data, error } = await supabase
.from('bookmarks')
.select()
.eq('place_id', placeId)
.eq('user_id', userId);
if (error) {
throw error;
}
return data;
};
접근법 : 현재 장소에 현재 로그인 한 유저가 북마크를 했는지 안했는지 알기 위해
두 개의 eq를 써서 데이터가 나오면 true, 없으면 false 로 받아
isBookmarked 상태로 쓰려고 했다
문제 1. 처음에 user_id를 eq 대신 match로 가져왔는데 이렇게하면
user_id가 'abc' 와 'abcd'인 사람이 있을 경우 두 개를 다 가져온다고..!
그래서 eq를 두 번 해서 필터링 했다
문제 2. supabase 의 서버 통신으로 나오는 데이터의 값이
[[{data}]]
형식으로 되어있기 때문에 항상 data[0] 으로
접근해야하는 귀찮음이 있었다
그래서 처음부터 single()
로 가져오려고 했는데 쿼리에서 계속 에러 발생! 🥺
이유는 single()
메서드는 뭐라도 1개는 값으로 내보내겠다! 라는 친구라
값이 없는 경우(undefined) 서버통신에 실패한 것으로 보고
몇 번 재시도를 하다가 결국 에러를 뿜었던 것!
그래서 결국 single()
을 빼고 값을 console.log에 찍어본 결과
값이 있는 경우 => [[{data}]]
값이 없는 경우 => undefined
이렇게 useQuery로 가져온 결과를 bookmarkState라는
useState의 상태값으로 만들어(boolean) 쓰기 위해
useEffect안에 담아서 초기값을 세팅해줬다
useEffect(() => {
setIsBookmarked(bookmarkState ? bookmarkState.length > 0 : false);
}, [bookmarkState]);
상태값으로 만든 bookmarkState 값에 따라서
아이콘을 조건부 렌더링 해주고
해당 아이콘을 눌렀을 때 북마크를 체크/해제 할 수 있게
toggle 함수를 만들어서 달아줬다
const toggleBookmark = () => {
if (isBookmarked) {
setIsBookmarked(false);
delBookmark.mutate({ userId: userInfo.userId, placeId });
} else {
setIsBookmarked(true);
addBookmark.mutate({ userId: userInfo.userId, placeId });
}
};
아래와 같은 방법으로 삭제도 만들고
좋아요 기능도 해치웠다! 😎
// 낙관적 업데이트 (추가)
const addBookmark = useMutation({
mutationFn: insertBookmark, // 북마크 추가함수
onMutate: async () => {
await queryClient.cancelQueries({
queryKey: ['bookmark', userInfo.userId, placeId],
});
const prev = queryClient.getQueryData([
'bookmark',
userInfo.userId,
placeId,
]); // 쿼리에 있었던 이전 값
const updateBookmark = [{ user_id: userInfo.userId, place_id: placeId }]; // 새로 넣을 값
queryClient.setQueryData(
['bookmark', userInfo.userId, placeId],
updateBookmark,
); // 쿼리에 넣어주기
return { prev };
},
onError: (error, updateReviewParams, context) => {
if (context?.prev) {
queryClient.setQueryData(
['bookmark', userInfo.userId, placeId],
context.prev,
);
}
}, // 실패하면 이전 값으로 되돌리기
onSettled: () => {
queryClient.invalidateQueries({
queryKey: ['bookmark', userInfo.userId, placeId],
});
}, // 실패하거나 성공하거나 실행됨
});