- 각 도서 상세 정보를 노출
- 좋아요 버튼을 클릭시 좋아요 또는 취소 기능
- 수량을 입력하여 장바구니 담기
null 일수도 있는 경우 타입에러
early return 방식을 사용할 수 있다! 배워감
import React from 'react';
import { useParams } from 'react-router-dom';
import styled from 'styled-components';
import { useBook } from '../hooks/useBook';
const BookDetail = () => {
const { bookId } = useParams();
const { book } = useBook(bookId);
if (!book) return null;
return <BookDetailStyle>{book.title}</BookDetailStyle>;
};
const BookDetailStyle = styled.div``;
export default BookDetail;
도서목록 중복 키배열
카테고리, 포맷, 등 같은 형식으로 중복되기 때문에 하드코딩이 아닌! 데이터의 키를 가지고 배열을 만들어서 처리하기
const BookInfoList = [
{
label: '카테고리',
key: 'category_name',
filter: (book: IBookDetail) => (
<Link to={`/books?category_id=${book.category_id}`}>
{book.category_name}
</Link>
),
},
{
label: '포맷',
key: 'form',
},
{
label: '페이지',
key: 'pages',
},
{
label: 'ISBN',
key: 'isbn',
},
{
label: '출간일',
key: 'pubDate',
filter: (book: IBookDetail) => {
return `${formatDate(book.pubDate)}`;
},
},
{
label: '가격',
key: 'price',
filter: (book: IBookDetail) => {
return `${formatNumber(book.price)} 원`;
},
},
];
//...
{BookInfoList.map((item) => (
<dl>
<dt>{item.label} </dt>
<dd>
{item.filter
? item.filter(book)
: book[item.key as keyof IBookDetail]}
</dd>
</dl>
))}
날짜 포매팅 Day.js : 가볍고, 많은 기능을 가졌음!
긴 줄글 더보기
`overflow: hidden;` 일정 height 이상 넘어가면 가려라는 css 항목
매번 대응할 수 없다는 단점이 있다. 높이보다, 줄 개수대로 적용하는게 필요하다.
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: ${({ linelimit }) => linelimit};;
-webkit-box-orient: vertical;
overflow 가 생기면 `ellipsis` 점점점으로 표시하고
`-webkit-box` 항목으로 지정한다. `line-clamp` 는 4줄까지만 표기하고, `box-orient` 는 방향을 뜻한다.
linelimt 을 props 상태로 전달할 수 있다.
토글
div는 attribute 로 string 만 받을 수 있고, boolean 은 받을 수 없다. 이때 앞에 $ 를 붙인다.
const EllipsisBox = ({ children, linelimit }: Props) => {
const [expanded, setExpanded] = useState(false);
return (
<EllipsisBoxStyle linelimit={linelimit} $expanded={expanded}>
<p>{children}</p>
<div className="toggle">
<Button
size="small"
scheme="normal"
onClick={() => setExpanded(!expanded)}
>
{expanded ? '접기' : '펼치기'} <FaAngleDown />
</Button>
</div>
</EllipsisBoxStyle>
);
};
좋아요
낙관적 업데이트 진행한다. 화면에서 즉각적으로 좋아요 수가 증가하는 걸 보여준다.
불필요한 fetch 중복 요청을 제거하는 경우가 많다!
const likeToggle = () => {
//권한 확인
if (!isloggedIn) {
showAlert('로그인이 필요합니다.');
return;
}
if (!book) return;
if (book.liked) {
//라이크 상태 > 언라이크 실행
unlikeBook(book.id).then(() => {
setBook({
...book,
liked: false,
likes: book.likes - 1,
});
});
} else {
//언라이크 상태 > 라이크를 실행
likeBook(book.id).then(() => {
//성공처리
setBook({
...book,
liked: true,
likes: book.likes + 1,
});
});
}
};
장바구니 list
setTimeout 으로 클릭하고 3초 뒤 사라지고, css 애니메이션 적용한다.
const addToCart = () => {
addCart({
book_id: book.id,
quantity: quantity,
}).then(() => {
setCartAdded(true);
setTimeout(() => {
setCartAdded(false);
}, 3000);
});
};
//...
opacity: ${({ $added }) => ($added ? '1' : '0')};
transition: all 0.5s ease;
☑️ 배운 점
백엔드 구현했던거랑 강의랑 안맞아서 고생 많이 했다...