티스토리 뷰
24.06.05_TIL ( 팀 프로젝트 : AI NOST Django ) _ 10. 댓글 scss 정리, book scss 정리, 좋아요와 별점 백엔드 연결
티아(tia) 2024. 6. 5. 10:34
[ 세번째 프로젝트 ]
AI를 이용한 소설 사이트를 만들어 보자.
++ 팀 스로젝트로 팀과의 협업이 중요하다.
++ 장고 공식 문서는 항상 확인하기
https://docs.djangoproject.com/en/4.2/
++ 랭체인 공식 문서
https://www.langchain.com/
++ 리액트 공식문서
https://ko.legacy.reactjs.org/ # 한국어
https://ko.react.dev/
https://github.com/1489ehdghks/NOST.git
1. main booklist scss 정리하기
이상태에서...ㅎㅎ...
예쁘게 한번 정리를 해보자.....ㅎㅎ...
댓글 부분 코드가 길어져서 분리가 필요함.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useParams } from 'react-router-dom';
import useThemeStore from '../../shared/store/Themestore';
import BookComment from './BookComment';
import './BookDetail.scss';
const BookDetail = () => {
const { id } = useParams();
const { themes, currentSeason } = useThemeStore();
const currentTheme = themes[currentSeason];
const [bookData, setBookData] = useState(null);
const [comments, setComments] = useState([]);
useEffect(() => {
axios.get(`http://127.0.0.1:8000/api/books/${id}/`)
.then(response => {
setBookData(response.data);
setIsLiked(response.data.is_liked_by_user); // 사용자가 좋아요를 눌렀는지 여부 설정
})
.catch(error => {
console.error('Error fetching book data:', error);
});
axios.get(`http://127.0.0.1:8000/api/books/${id}/comments/`)
.then(response => {
setComments(response.data || []);
console.log('comment :', response.data);
})
.catch(error => {
console.error('Error fetching comments:', error);
});
}, [id]);
return (
<div className="bookdetail" style={{ color: currentTheme.buttonTextColor }}>
{bookData && (
<div className="summary" style={{ backgroundColor: currentTheme.buttonBackgroundColor }}>
<h1>{bookData.title}</h1>
{/* <img src={bookData.image} alt={bookData.header} /> */}
{/* <p>{bookData.content}</p> */}
<h3>Author : {bookData.user_nickname}</h3>
<p>'❤️{bookData.is_liked.length} ⭐ {bookData.average_rating}/5</p>
</div>
)}
<BookComment
bookId={id}
comments={comments}
setComments={setComments}
currentTheme={currentTheme}
/>
</div>
);
};
export default BookDetail;
.bookdetail {
display: flex;
justify-content: space-between;
padding: 20px;
margin-top: 50px;
height: 100%; // 화면 전체 높이 설정
overflow: auto; //스크롤 활성화
scrollbar-width: none; /* 스크롤바 안보임 */
}
.summary {
flex: 1.5;
margin-right: 20px;
padding: 20px;
background-color: inherit;
border-radius: 10px;
margin-bottom: 100px;
h1 {
margin-bottom: 10px;
}
h3, p {
margin-bottom: 10px;
display: flex;
justify-content: flex-end;
}
p {
font-size: 16px;
line-height: 1.5;
}
}
import React, { useState } from 'react';
import axiosInstance from '../../features/auth/AuthInstance';
import './BookComment.scss';
const BookComment = ({ bookId, comments, setComments, currentTheme }) => {
const [newComment, setNewComment] = useState('');
const [editingCommentId, setEditingCommentId] = useState(null);
const [updatedContent, setUpdatedContent] = useState('');
const [visibleComments, setVisibleComments] = useState(5); // 현재 보이는 댓글 수를 관리하는 상태
const handleAddComment = async () => {
try {
console.log('Adding comment:', newComment);
const response = await axiosInstance.post(`http://127.0.0.1:8000/api/books/${bookId}/comments/`, {
content: newComment,
});
console.log('Comment added successfully:', response.data);
setComments([...comments, response.data]);
setNewComment('');
} catch (error) {
console.error('Error adding comment:', error);
alert('댓글을 추가하는 중에 오류가 발생했습니다.');
}
};
const handleEditComment = async (commentId, updatedContent) => {
try {
const response = await axiosInstance.put(`http://127.0.0.1:8000/api/books/${bookId}/comments/${commentId}/`, {
content: updatedContent,
});
setComments(comments.map(comment => comment.id === commentId ? response.data : comment));
setEditingCommentId(null);
setUpdatedContent('');
} catch (error) {
console.error('Error editing comment:', error);
alert('댓글을 수정하는 중에 오류가 발생했습니다.');
}
};
const handleDeleteComment = async (commentId) => {
try {
await axiosInstance.delete(`http://127.0.0.1:8000/api/books/${bookId}/comments/${commentId}/`);
setComments(comments.filter(comment => comment.id !== commentId));
} catch (error) {
console.error('Error deleting comment:', error);
alert('댓글을 삭제하는 중에 오류가 발생했습니다.');
}
};
const buttonStyle = {
backgroundColor: 'transparent',
border: `1.5px solid ${currentTheme.buttonBackgroundColor}`,
color: currentTheme.textColor,
marginLeft: '5px'
};
return (
<div className="comment-box" style={{ color: currentTheme.textColor }}>
<h2>Comment Box</h2>
<div className="comments">
{comments.slice(0, visibleComments).map((comment) => (
<div className="comment" key={comment.id}>
<div className="comment-avatar" style={{ backgroundColor: currentTheme.buttonBackgroundColor, color: currentTheme.buttonTextColor }}>
{comment.user_nickname.charAt(0).toUpperCase()}
</div>
<div className="comment-content">
<p>{comment.content} </p>
<p style={{ color: currentTheme.sidebarBg }}>{comment.user_nickname} <br />
<small>on {new Date(comment.created_at).toLocaleDateString('en-US', { year: 'numeric', month: '2-digit', day: '2-digit' })}</small>
</p>
<div>
<button style={buttonStyle} onClick={() => { setEditingCommentId(comment.id); setUpdatedContent(comment.content); }}>Edit</button>
<button style={buttonStyle} onClick={() => handleDeleteComment(comment.id)}>Delete</button>
{editingCommentId === comment.id && (
<div>
<textarea value={updatedContent}
onChange={(e) => setUpdatedContent(e.target.value)}></textarea>
<button style={buttonStyle} onClick={() => handleEditComment(comment.id, updatedContent)}>Save</button>
<button style={buttonStyle} onClick={() => setEditingCommentId(null)}>Cancel</button>
</div>
)}
</div>
</div>
</div>
))}
{visibleComments < comments.length && (
<button style={buttonStyle} onClick={() => setVisibleComments(visibleComments + 5)}>더보기</button>
)}
</div>
<textarea
placeholder="Your comments"
value={newComment}
onChange={(e) => setNewComment(e.target.value)}>
</textarea>
<button style={{ backgroundColor: currentTheme.buttonBackgroundColor, color: currentTheme.buttonTextColor, marginBottom: '150px' }}
onClick={handleAddComment}> Add </button>
</div>
);
};
export default BookComment;
.comment-box {
flex: 1;
margin-left: 50px;
margin-bottom: 50px;
h2 {
margin-bottom: 10px;
}
textarea {
width: 95%;
color: inherit;
height: 50px;
padding: 10px;
margin-bottom: 10px;
border-radius: 5px;
border: 1px solid #ccc;
resize: none; /* 사용자가 크기를 조절하지 못하도록 설정합니다. */
scrollbar-width: none; /* 스크롤바 안보임 */
}
button {
padding: 10px 20px;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
&:hover {
background-color: #eceaea !important;
}
}
}
.comments {
margin-bottom: 20px;
}
.comment {
display: flex;
align-items: flex-start;
margin-bottom: 10px;
p {
font-size: 14px;
line-height: 1.4;
}
n{
margin-right: 10px;
}
button {
padding: 5px 10px;
color: inherit;
border: none;
border-radius: 5px;
cursor: pointer;
&:hover {
background-color: #f6f5f5 !important;
}
}
}
.comment-avatar {
width: 55px;
height: 50px;
min-width: 50px; /* 추가 */
min-height: 50px; /* 추가 */
background-color: inherit;
border-radius: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
font-weight: bold;
color: inherit;
margin-right: 10px;
}
.comment-content{
textarea {
width: 95%;
height: 70px;
color: inherit;
padding: 10px;
margin-top: 10px;
margin-bottom: 5px;
border-radius: 5px;
border: 1px solid #ccc;
resize: none; /* 사용자가 크기를 조절하지 못하도록 설정합니다. */
scrollbar-width: none; /* 스크롤바 안보임 */
}
}
5개씩 잘려서 댓글이 나오게 하고 더보기를 누르면 5개씩 더 보여주는 기능을 넣음.
동그란 부분은 사용자 닉네임의 첫글자를 가지고 와서 동그랗게 그림처럼 보여주는 기능을 넣음.
2. 이제 북 부분이 나오게 하자. 좋아요 기능 넣기
좋아요 참고 사이트 : https://heurm-tutorial.vlpt.us/12/04.html
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useParams } from 'react-router-dom';
import useThemeStore from '../../shared/store/Themestore';
import axiosInstance from '../../features/auth/AuthInstance';
import BookComment from './BookComment';
import './BookDetail.scss';
const BookDetail = () => {
const { id } = useParams();
const { themes, currentSeason } = useThemeStore();
const currentTheme = themes[currentSeason];
const [bookData, setBookData] = useState(null);
const [comments, setComments] = useState([]);
const [isLiked, setIsLiked] = useState(false);
useEffect(() => {
axios.get(`http://127.0.0.1:8000/api/books/${id}/`)
.then(response => {
setBookData(response.data);
setIsLiked(response.data.is_liked_by_user); // 사용자가 좋아요를 눌렀는지 여부 설정
})
.catch(error => {
console.error('Error fetching book data:', error);
});
axios.get(`http://127.0.0.1:8000/api/books/${id}/comments/`)
.then(response => {
setComments(response.data || []);
console.log('comment :', response.data);
})
.catch(error => {
console.error('Error fetching comments:', error);
});
}, [id]);
const toggleLike = async () => {
try {
const response = await axiosInstance.post(`http://127.0.0.1:8000/api/books/${id}/like/`);
const { like_bool, total_likes, book } = response.data;
setIsLiked(like_bool);
setBookData(book);
} catch (error) {
console.error('Error toggling like:', error);
}
};
return (
<div className="bookdetail" style={{ color: currentTheme.buttonTextColor }}>
{bookData && (
<div className="summary" style={{ backgroundColor: currentTheme.buttonBackgroundColor }}>
<h1>{bookData.title}</h1>
{/* <img src={bookData.image} alt={bookData.header} /> */}
{/* <p>{bookData.content}</p> */}
<h3>Author : {bookData.user_nickname}</h3>
<p><button className="like"
onClick={toggleLike}> {isLiked ? '❤️' : '♡'} </button> {bookData.is_liked.length}
⭐ {bookData.average_rating}/5</p>
</div>
)}
<BookComment
bookId={id}
comments={comments}
setComments={setComments}
currentTheme={currentTheme}
/>
</div>
);
};
export default BookDetail;
.like {
background-color: transparent; /* 배경 투명 */
border: none; /* 버튼 라인 투명 */
cursor: pointer; /* 마우스 포인터 모양 변경 */
}
백엔드 books 의 views.py 도 수정해야해서 해준다.
class BookLikeAPIView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request, book_id):
book = get_object_or_404(Book, id=book_id)
like_bool = False
# 좋아요 삭제
if request.user in book.is_liked.all():
book.is_liked.remove(request.user)
# 좋아요 추가
else:
book.is_liked.add(request.user)
like_bool = True
serializer = BookLikeSerializer(book)
return Response(
{
"like_bool": like_bool,
"total_likes": book.total_likes(),
"book": serializer.data,
},
status=200,
)
이렇게 수정하면 하트를 눌렀을 때 디비에 저장되고 취소하면 없어진다.
내가 좋아요한 숫자만 올라간다.
3. 별점 기능 넣기 백엔드랑 연결
rating 관련해서 백엔드 변경
models.py
class Rating(models.Model) :
RATING_CHOICES = [
(1,"1"),
(2,"2"),
(3,"3"),
(4,"4"),
(5,"5"),
]
book = models.ForeignKey(Book, related_name='ratings', on_delete=models.CASCADE)
user_id = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="rating_user", on_delete=models.CASCADE)
rating = models.PositiveIntegerField(blank=True)
class Meta :
constraints = [
models.UniqueConstraint(fields=['book', 'user_id'], name = 'unique_book_user_rating')
]
------------------------------
views.py
class RatingAPIView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request, book_id):
book = get_object_or_404(Book, id=book_id)
rating = request.data.get("rating")
if rating not in [1, 2, 3, 4, 5]:
return Response("Rating must be between 1 and 5", status=400)
existing_rating = Rating.objects.filter(book=book, user_id=request.user).exists()
if existing_rating:
return Response("You have already rated this book.", status=400)
serializer = RatingSerializer(data={"rating": rating})
if serializer.is_valid(raise_exception=True):
serializer.save(user_id=request.user, book=book)
return Response(serializer.data, status=200)
return Response(status=400)
별점 5개 아이콘 넣기 위해서 리엑트의 아이콘을 다운받아준다.
npm install react-icons
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useParams } from 'react-router-dom';
import useThemeStore from '../../shared/store/Themestore';
import axiosInstance from '../../features/auth/AuthInstance';
import BookComment from './BookComment';
import './BookDetail.scss';
import { FaStar } from 'react-icons/fa';
const BookDetail = () => {
const { id } = useParams();
const { themes, currentSeason } = useThemeStore();
const currentTheme = themes[currentSeason];
const [bookData, setBookData] = useState(null);
const [comments, setComments] = useState([]);
const [isLiked, setIsLiked] = useState(false);
const [rating, setRating] = useState(0);
useEffect(() => {
axios.get(`http://127.0.0.1:8000/api/books/${id}/`)
.then(response => {
setBookData(response.data);
setIsLiked(response.data.is_liked); // 사용자가 좋아요를 눌렀는지 여부 설정
console.log('data : ', response.data);
})
.catch(error => {
console.error('Error fetching book data:', error);
});
axios.get(`http://127.0.0.1:8000/api/books/${id}/comments/`)
.then(response => {
setComments(response.data || []);
})
.catch(error => {
console.error('Error fetching comments:', error);
});
}, [id]);
const toggleLike = async () => {
try {
const response = await axiosInstance.post(`http://127.0.0.1:8000/api/books/${id}/like/`);
const { like_bool, total_likes, book } = response.data;
setIsLiked(like_bool);
setBookData(book);
} catch (error) {
console.error('Error toggling like:', error);
}
};
const rateBook = async (newRating) => {
try {
const response = await axiosInstance.post(`http://127.0.0.1:8000/api/books/${id}/rating/`, { rating: newRating });
const { rating, book } = response.data;
console.log('ragingssssss : ', response.data);
setBookData(book);
setRating(rating); // 서버에서 업데이트된 평균 별점 설정
} catch (error) {
console.error('Error rating book:', error);
}
};
const handleStarClick = (index) => {
const newRating = index + 1; // 클릭된 별의 인덱스에 1을 더하여 새로운 별점을 설정합니다.
rateBook(newRating); // 새로운 별점을 서버로 전송합니다.
console.log('raging : ', newRating);
};
return (
<div className="bookdetail" style={{ color: currentTheme.buttonTextColor }}>
{bookData && (
<div className="summary" style={{ backgroundColor: currentTheme.buttonBackgroundColor }}>
<h1>{bookData.title}</h1>
{/* <img src={bookData.image} alt={bookData.header} /> */}
{/* <p>{bookData.content}</p> */}
<h3>Author : {bookData.user_nickname}</h3>
<p>
<button className="like" onClick={toggleLike}>
{isLiked ? '❤️' : '♡'}
</button>
{bookData.total_likes} {bookData.is_liked ? 'Liked' : 'Likes'}
</p>
<div>
{[...Array(5)].map((_, index) => (
<FaStar
key={index}
onClick={() => handleStarClick(index)} // 클릭된 별의 인덱스를 handleStarClick 함수에 전달합니다.
color={index < rating ? '#ffc107' : '#e4e5e9'}
size={24}
style={{ cursor: 'pointer' }}
/>
))}
<p>Average Rating: {bookData.average_rating}/5</p>
</div>
</div>
)}
<BookComment
bookId={id}
comments={comments}
setComments={setComments}
currentTheme={currentTheme}
/>
</div>
);
};
export default BookDetail;
별점은 백엔드에 잘 저장된 것을 볼 수 있다.
그러나 프론트엔드에서 문제가 발생한다ㅜㅜ
++ 별점을 주자마자 제목 없어짐...ㅎㅎ
++ 별점을 한번만 줄 수 있는건 좋지만 총점이 바로 반영이 안됨
++ likes 도 바로 반영안되고 토탈을 눌러야 뜸... 바꿔야지ㅜㅜ
로컬 브렌치 삭제
git branch -D <브렌치 이름>
깃허브 원격 브렌치 삭제
git push origin -d <브렌치 이름>
4. 별점, 좋아요 오류 기능 수정
const rateBook = async (newRating) => {
try {
const response = await axiosInstance.post(`http://127.0.0.1:8000/api/books/${id}/rating/`, { rating: newRating });
const { rating, book } = response.data;
setRating(rating); // 서버에서 업데이트된 평균 별점 설정
} catch (error) {
console.error('Error rating book:', error);
// 서버에서 받은 에러 메시지가 '이미 처리되었습니다'인지 확인하여 알림을 표시합니다.
if (error.response && error.response.data === 'You have already rated this book.') {
alert('이미 처리되었습니다');
}
}
};
별점을 중복으로 줄 때 에러메세지 발생하게 만들어주자.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useParams } from 'react-router-dom';
import useThemeStore from '../../shared/store/Themestore';
import axiosInstance from '../../features/auth/AuthInstance';
import BookComment from './BookComment';
import './BookDetail.scss';
import { FaStar } from 'react-icons/fa';
import { FaHeart } from 'react-icons/fa';
const BookDetail = () => {
const { id } = useParams();
const { themes, currentSeason } = useThemeStore();
const currentTheme = themes[currentSeason];
const [bookData, setBookData] = useState(null);
const [comments, setComments] = useState([]);
const [rating, setRating] = useState(0); // 별점 상태 추가
const [books, setBooks] = useState([]);
const [like_bool, setIsLiked] = useState(false);
useEffect(() => {
axios.get(`http://127.0.0.1:8000/api/books/${id}/`)
.then(response => {
setBookData(response.data);
setIsLiked(response.data.is_liked);
console.log('data : ', response.data);
})
.catch(error => {
console.error('Error fetching book data:', error);
});
axios.get(`http://127.0.0.1:8000/api/books/${id}/comments/`)
.then(response => {
setComments(response.data || []);
})
.catch(error => {
console.error('Error fetching comments:', error);
});
}, [id]);
const toggleLike = async () => {
try {
const response = await axiosInstance.post(`http://127.0.0.1:8000/api/books/${id}/like/`);
const { like_bool, total_likes } = response.data;
setIsLiked(like_bool);
setBookData(prevBookData => ({
...prevBookData,
is_liked: like_bool,
total_likes: total_likes
}));
const updatedBooks = books.map(book => {
if (book.id === id) {
return {...book, is_liked: like_bool};
}
return book;
});
setBooks(updatedBooks);
} catch (error) {
console.error('Error toggling like:', error);
}
};
const rateBook = async (newRating) => {
try {
const response = await axiosInstance.post(`http://127.0.0.1:8000/api/books/${id}/rating/`, { rating: newRating });
const { rating } = response.data;
setBookData(prevBookData => ({
...prevBookData,
user_rating: rating
}));
setRating(rating); // 사용자가 별점을 준 경우 별점 상태 업데이트
// 사용자의 최신 별점을 가져와서 업데이트
userRate();
} catch (error) {
console.error('Error rating book:', error);
if (error.response && error.response.data === 'You have already rated this book.') {
alert('이미 처리되었습니다');
}
}
};
const userRate = async () => {
try {
const response = await axiosInstance.get(`http://127.0.0.1:8000/api/books/${id}/rating/`);
const { rating } = response.data;
setRating(rating); // 사용자의 별점 업데이트
} catch(error) {
if (error.response && error.response.status === 404) {
// 만약 책에 대한 평가가 없는 경우 평점을 0으로 설정
setRating(0);
} else {
console.error('Error fetching user rating:', error);
}
}
};
useEffect(() => {
// 페이지 로드 시 사용자의 별점을 가져오기 위해 호출
userRate();
}, []);
const handleStarClick = (index) => {
const newRating = index + 1;
rateBook(newRating);
console.log('raging : ', newRating);
};
return (
<div className="bookdetail" style={{ color: currentTheme.buttonTextColor }}>
{bookData && (
<div className="summary" style={{ backgroundColor: currentTheme.buttonBackgroundColor }}>
<h1>{bookData.title}</h1>
<h3>Author : {bookData.user_nickname}</h3>
<div>
<p> like {bookData.total_likes}
<span onClick={toggleLike}>
<FaHeart
color={bookData.is_liked ? '#ff0707' : '#ffffff'}
size={20}
style={{ marginLeft: '10px', cursor: 'pointer' }}
/>
</span>
</p>
<p> {rating ? `Your Rating: ${rating}/5` : `Please Rate This Book`}
<span style={{ marginLeft: '10px' }}>
{[...Array(5)].map((_, index) => (
<FaStar
key={index}
onClick={() => handleStarClick(index)}
color={index < rating ? '#fce146' : '#ffffff'}
size={24}
style={{ cursor: 'pointer' }}
/>
))}</span>
</p>
</div>
</div>
)}
<BookComment
bookId={id}
comments={comments}
setComments={setComments}
currentTheme={currentTheme}
/>
</div>
);
};
export default BookDetail;
이 코드는 일단 좋아요를 누를때 하나씩 올랐다가 한번 더 누르면 취소가 되어서 숫자가 줄어든다.
(++ 처음 들어갔을 때는 총 개수가 먼저 안뜨고 하트만 있어서 나중에 수정해야할것같다.)
별점은 별점 평균이 안보이고 내가 준 별점만 보이도록 수정하였다.
이때 포스트만으로는 개인 사용자의 별점을 가져올 수 없어서 백엔드도 수정해야했다.
class RatingAPIView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request, book_id):
book = get_object_or_404(Book, id=book_id)
rating = request.data.get("rating")
if rating not in [1, 2, 3, 4, 5]:
return Response("Rating must be between 1 and 5", status=400)
existing_rating = Rating.objects.filter(book=book, user_id=request.user).exists()
if existing_rating:
return Response("You have already rated this book.", status=400)
serializer = RatingSerializer(data={"rating": rating})
if serializer.is_valid(raise_exception=True):
serializer.save(user_id=request.user, book=book)
return Response(serializer.data, status=200)
return Response(status=400)
def get(self, request, book_id):
book = get_object_or_404(Book, id=book_id)
user_rating = Rating.objects.filter(book=book, user_id=request.user.id).first()
if user_rating:
serializer = RatingSerializer(user_rating)
return Response(serializer.data, status=200)
return Response("User has not rated this book yet.", status=404)
views.py 에서 rating 겟방식으로 가져올수있게 수정
내가 준 별점으로 잘 보이지만 별점을 주지 않은 북으로 갔을 때는 에러가 발생하였다.
<< 이러한 문제가 발생하는 이유는 프론트엔드에서 컴포넌트가 마운트될 때 자동으로 실행되는 useEffect 훅에서 userRate 함수가 호출되기 때문입니다. useEffect 훅은 컴포넌트가 마운트될 때, 그리고 id가 변경될 때마다 호출되는데, 이 때 userRate 함수가 실행되어 서버에 사용자의 평점을 가져오려고 시도합니다.
그러나 사용자가 별점을 주지 않은 경우에도 userRate 함수가 호출되어 서버에 요청을 보내게 되는데, 이 때 백엔드에서는 해당 엔드포인트를 찾을 수 없어 404 에러가 발생합니다.
이 문제를 해결하기 위해서는 userRate 함수가 실행되는 조건을 변경해야 합니다. 사용자가 별점을 준 후에만 userRate 함수가 실행되도록 수정해야 합니다. 이를 위해서는 사용자가 별점을 준 경우에만 userRate 함수를 호출하도록 코드를 수정해야 합니다. >>
이런 문제가 발생한다고 하여 코드를 수정해주어야한다.
점수를 안줘서 먼저 404에러가 뜨는 것 같은데...
const userRate = async () => {
try {
const response = await axiosInstance.get(`http://127.0.0.1:8000/api/books/${id}/rating/`);
const { rating } = response.data;
setRating(rating); // 사용자의 별점 업데이트
} catch(error) {
if (error.response && error.response.status === 404) {
// 만약 책에 대한 평가가 없는 경우 평점을 0으로 설정
setRating(0);
} else {
console.error('Error fetching user rating:', error);
}
}
};
일단 console 창에는 이렇게 뜨게 수정을 해두었다.
값이 없는 경우의 에러메세지는 크게 영향을 미치지 않는다고 하는데... 글쎄..ㅠㅠ 그건 배포해봐야 알듯... 일단 이렇게 두고 넘어가겠다...ㅠㅠ