



내가 요즘 잘 이용하고 있는 북적북적 이라는 어플을 웹으로 만들어보면서 학습하고 있다.
전에 고캠핑을 만들었을 땐 파이어베이스를 이용해서 했는데 이번엔 zustand를 접해 볼 기회가 있어 적응해볼 겸 적용해보았다.
zustand를 이용해 로컬 스토리지에 책 데이터(독서한 책)를 저장하고 있다.
책 정보 types
// 책 정보 조회 알라딘 api
import { BookData } from 'types/bookData';
import { create } from 'zustand';
interface BookStore {
bookData: BookData[] | null;
fetchBookData: (isbn: string) => Promise<void>;
}
// 책 정보 조회 api
const useBookStore = create<BookStore>((set) => ({
bookData: null,
fetchBookData: async (isbn) => {
try {
const response = await fetch(
`
https://tranquil-tundra-65213-03a93afc8c4f.herokuapp.com/http://www.aladin.co.kr/ttb/api/ItemLookUp.aspx?ttbkey=${
process.env.REACT_APP_TTB_KEY
}&itemIdType=ISBN13&ItemId=${isbn}&output=js&Version=20131101
`
);
const data = await response.json();
set({ bookData: data.item });
} catch (error) {
console.log(error);
}
}
}));
export default useBookStore;
알라딘 블로그에 보면
요청 URL샘플 : http://www.aladin.co.kr/ttb/api/ItemLookUp.aspx?ttbkey=TTBKey&itemIdType=ISBN13&ItemId=도서의ISBN&output=xml&Version=20131101
이라고 나와있다! TTBKey엔 발급받은 자신의 key를 itemId는 도서의 isbn을 넣으면 되는데 도서 정보에서 isbn이 아니라 isbn13을 넣어야 상품 조회가 된다!
https://blog.aladin.co.kr/openapi/category/29154402?communitytype=MyPaper
// 책 저장하기
북적북적 어플에서는 읽은책, 읽고 있는 책, 읽고 싶은 책, 중단한 책 네가지로 나뉘는데 난 읽은책, 읽고 있는 책만 사용해서 두 가지만 넣었다. (연습용으로 만든거라 이 외에도 빠진 기능들이 있다.)
<기존 코드>
import { LibraryData } from 'types/bookData';
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
// 데이터 유지: persist 추가 (로컬스토리지에 저장)
const useLibraryStore = create<LibraryData>()(
persist(
(set) => ({
books: [],
readBooks: [],
readingBooks: [],
addBook: (data) =>
set((state) => {
const updateBooks = [
...state.books,
{
bookState: data.bookState,
startDate: data.startDate,
endDate: data.endDate,
starRating: data.starRating,
review: data.review,
pagePercent: data.pagePercent,
pageNum: data.pageNum,
// 책 정보
title: data.title,
cover: data.cover,
author: data.author,
itemPage: data.itemPage,
link: data.link,
description: data.description,
publisher: data.publisher,
isbn: data.isbn,
isbn13: data.isbn13
}
];
// 책 update
const readBooks = updateBooks.filter(
(book) => book.bookState === true
);
const readingBooks = updateBooks.filter(
(book) => book.bookState === false
);
return {
books: updateBooks,
readBooks: readBooks,
readingBooks: readingBooks
};
}),
}),
{ name: 'library' } // 로컬 스토리지에 'library'라는 키로 저장
)
);
export { useLibraryStore };
원래는 books 저장한 책 전체 목록만 만들었다가 서재나 다른 페이지에서 읽은 책, 읽고 있는 책 상태별로 데이터가 필요했다. 매 화면마다 데이터를 필터링 하는 것 보다 필터링 된 데이터를 가져오는 것이 좋을 것 같다고 생각이 들었다.
그래서 책을 저장할 때 addBooks 에서 readBooks, readingBooks를 같이 업데이트 하는 방법으로 하려 했으나 이렇게 하는 건 books가 업데이트 될 때마다 readBooks, readingBooks도 매번 업데이트 되어야 하니까 불필요한 작업이 되는 것 같아서 방법을 바꿨다.
<수정 코드>
const useLibraryStore = create<LibraryData>()(
persist(
(set) => ({
books: [],
addBook: (data) =>
set((state) => ({
books: [
...state.books,
{
bookState: data.bookState,
startDate: data.startDate,
endDate: data.endDate,
starRating: data.starRating,
review: data.review,
pagePercent: data.pagePercent,
pageNum: data.pageNum,
// 책 정보
title: data.title,
cover: data.cover,
author: data.author,
itemPage: data.itemPage,
link: data.link,
description: data.description,
publisher: data.publisher,
isbn: data.isbn,
isbn13: data.isbn13
}
]
})),
deleteBook: (bookId: string) =>
set((state) => ({
books: state.books.filter((book) => book.isbn13 !== bookId)
}))
}),
{ name: 'library' } // 로컬 스토리지에 'library'라는 키로 저장
)
);
import { useLibraryStore } from 'store/useLibraryStore';
export const useReadBook = () => {
const { books } = useLibraryStore();
const readBooks = books.filter((book) => book.bookState === true);
const readingBooks = books.filter((book) => book.bookState === false);
return { readBooks, readingBooks };
};
// 사용 예시
export default function TabList() {
const { readBooks } = useReadBook();
return (
<BookList>
{readBooks
.slice()
.reverse()
.map((book) => (
<li key={book.isbn13}>
<Link to='/home'>
<img src={book.cover} alt={book.isbn13} />
<p className='title text_ellipsis'>{book.title}</p>
<p className='sub_title mt_4 text_ellipsis'>{book.author}</p>
<StarRating readonly rating={book.starRating} />
</Link>
</li>
))}
</BookList>
);
}
원래대로 책 데이터는 books로만 관리하고 커스텀 훅을 만들어서 사용했다.
로컬스토리지에서 저장한 책 데이터를 확인할 수 있다.

'언어 > React.js' 카테고리의 다른 글
[React.js] canvas 를 이용한 게임 (0) | 2025.02.03 |
---|---|
[cors 오류] 알라딘 api cors 연결하기 (0) | 2025.01.11 |
useCallback() (0) | 2024.10.22 |
Side Effects 다루기 (0) | 2024.10.18 |
[React] 내가 보려고 쓴 리액트 (0) | 2023.10.26 |