구현 목표
인증된 유저에 따라 각자 관심 도서가 다를것이다.
그래서 로그인 한 유저만 관심 목록에 추가가 가능하게 할 것이고,
추가 된 도서의 ISBN번호는 firestore에 저장해서 관리한다.
그리고 아래와 같이 검색 하면
firebase db에서 관심 도서의 데이터를 불러와
이미 추가된 관심 도서의 경우 아이콘(하트)가 붉게 표시되게 만들것이다.
그리고, 이미 관심 도서에 추가되어있는 도서의 경우 아이콘을 한 번더 클릭 할 경우
DB에서 삭제하는 기능을 구현하고 싶다.
1. 하트아이콘 클릭 시 관심 목록( DB)에 추가하기
//관심 도서에 추가 및 제거 트리거
const handleClick = async () => {
//일단 이미 관심 도서에 추가되어 있는지 확인한다.
// 1. 관심도서에 없는 도서의 경우
if (!onHeart) {
//confirm 창으로 추가할건지 여부 물어봄
// 1-1) 확인 클릭
if (confirm("관심 도서에 추가하겠습니까?")) {
if (!user) {
//유저가 없으면(로그인 되어있지 않을 경우)
alert("로그인이 필요한 서비스입니다.");
navigate("/user/login"); //로그인 페이지로 이동
} else {
//로그인 되어있으면 하트 색상 변경하고
setOnHeart(true);
//DB에 저장한다.
try {
await addDoc(collection(db, "interestBooks"), {
//컬렉션명 -interestBooks
interestBook: book.isbn, //book id
booktitle: book.title, //book title
createdAt: Date.now(), // 생성일자 오늘
username: user.displayName, // 유저 이름
userId: user.uid, // 유저 아이디
});
} catch (error) {
console.log(error); //에러는 콘솔에 출력
}
}
// 1-2) 취소 클릭 - 리턴
} else {
alert("취소");
return;
}
원래는 book.isbn 을 담을 usestate를 사용해서
아이콘을 클릭하면 state에 담고 , 그 값을 다시 불러와서 저장을 할려고 했는데
그렇게 하니 딜레이가 생기고, 값이 여러 번 저장되는 오류가 생겼다 ㅠㅠ
그래서 state에 저장하지 않고 바로 book.isbn값을 interstBook의 값에 넣는걸로 수정했다.
테스트
현재 db에는 아무런 값이 저장되어 있지 않다.
아래의 도서를 추가 해보고자 한다.
1. 로그인 X
2. 로그인 O
DB에 저장이 됐음
2. 이미 관심 도서에 추가되어있는 도서의 경우 삭제하기
// 2. 이미 관심 도서에 있는 경우(삭제)
} else if (onHeart) {
if (confirm("관심 도서에서 제거하겠습니까?")) {
setOnHeart(false); //제거 확인 버튼 누르면 하트 색상 변경
//2-1)유저가 있으면(로그인)
if (user) {
try {
//쿼리문 작성
const q = query(
collection(db, "interestBooks"), // 삭제할 컬렉션 지정
where("userId", "==", user.uid), // 현재 로그인되어있는 유저와 같은 것
where("interestBook", "==", book.isbn) //book.isbn 으로 찾음
);
const querySnapshot = await getDocs(q);
querySnapshot.forEach(async (doc) => {
try {
await deleteDoc(doc.ref); //삭제한다.
console.log("관심 도서 삭제 성공!");
} catch (error) {
console.error("Error deleting document:", error);
}
});
} catch (error) {
console.error("Error querying document:", error);
}
}
} else {
return;
}
}
};
이미 추가된 도서의 경우 아이콘을 클릭할 경우 제거할지 여부를 물어본다.
3.유저 별 관심 도서를 firestore에서 가져와서 표시하기
위의 코드만 구현하면 새로고침할 때 마다 이미 추가된 도서의 경우에도 하트의 색상이 초기화된다.
그래서 이미 관심 도서에 추가되어있는 도서의 경우에는
DB를 읽어서 새로고침하더라도 반영이 되어있도록 코드를 추가했다.
useEffect(() => {
//관심목록 가져오는 함수
const fetchInterestBooks = async () => {
if (user) {
//유저가 있을 경우
const q = query(
collection(db, "interestBooks"),
where("userId", "==", user.uid) //로그인 한 유저와 동일한 데이터만
);
const snapshot = await getDocs(q); // 데이터를 다 가져올 때 까지 기다림
const userInterestBooks = snapshot.docs.map(
(doc) => doc.data().interestBook
);
//가져온 관심 도서에 해당 되는 도서의 경우 ture로 리턴
const isBookInInterest = userInterestBooks.includes(book.isbn);
setOnHeart(isBookInInterest);
}
};
fetchInterestBooks();
}, [book.isbn, user]); // 로그인 유저와 book.isbn 변경될 때 마다 실행
https://velog.io/@minjae46/React-%EA%B2%80%EC%83%89-%EA%B8%B0%EB%8A%A5-feat.-filter-includes-%EB%A9%94%EC%84%9C%EB%93%9C
이 코드를 통해서 새로 고침하더라도 초기화 되지 않는다.
코드 수정
현재 마이페이지에서 관심 도서를 유저별로 불러올려고 하는데
fetch를 써서 알라딘에서 불러오는것보다
애초에 DB에서 필요한 자료만 따로 저장하는게 수월해보여서
코드를 수정했다.
await addDoc(collection(db, "interestBooks"), {
//컬렉션명 -interestBooks
interestBook: book.isbn, //book id
bookTitle: book.title, //book title
bookCover: book.cover, //book cover
bookLink: book.link, //book link
bookAuthor: book.author, //book author
bookPublisher: book.publisher, //book publisher
createdAt: Date.now(), // 생성일자 오늘
username: user.displayName, // 유저 이름
userId: user.uid, // 유저 아이디
});