티스토리 뷰
Zustand란?
Zustand 라이브러리는 상태 관리를 위한 도구입니다. 이 라이브러리는 리덕스와 달리 별도의 리듀서 함수나 액션을 작성하지 않고도 간편하게 상태를 관리할 수 있습니다. 이번 글에서는 Zustand를 사용하여 영화 선호 목록을 관리하는 코드를 통해 이 라이브러리의 사용법을 알아보겠습니다.
Zustand를 이용한 영화 선호 목록 관리
우선, Zustand를 활용하여 영화 선호 목록을 관리하는 커스텀 훅을 작성해보겠습니다.
import { addFavoriteMovie } from "@/app/api/add-favorite-movie";
import { delFavoriteMovie } from "@/app/api/del-favorite-movie";
import { getFavoriteMovies } from "@/app/api/get-favorite-movies";
import { create } from "zustand";
import { persist } from "zustand/middleware";
interface IFavoriteMovies {
favoriteMovies: any[];
fetch: (id: any) => Promise<void>;
delFavoriteMovie: (id: any) => Promise<void>;
addFavoriteMovie: (data: any) => Promise<void>;
}
const useFavoriteMovies = create<IFavoriteMovies>()(
persist(
(set) => ({
favoriteMovies: [], // 선호 영화 목록 상태
fetch: async (id: any) => {
// 선호 영화 목록 가져오기
const response = await getFavoriteMovies(id);
set({ favoriteMovies: response });
},
delFavoriteMovie: async (data: any) => {
// 선호 영화 삭제
await delFavoriteMovie(data);
set((state) => ({
favoriteMovies: state.favoriteMovies.filter((movie) => movie.movie_id !== data.movie_id),
}));
},
addFavoriteMovie: async (data: any) => {
// 선호 영화 추가
await addFavoriteMovie(data);
set((state) => ({ favoriteMovies: [...state.favoriteMovies, data] })); // 상태 업데이트
},
}),
{
name: "favoriteMovies-storage", // 로컬 스토리지에 저장될 키 이름
}
)
);
export default useFavoriteMovies;
create 함수를 사용하여 상태와 액션을 정의하고, persist 미들웨어를 사용하여 로컬 스토리지에 상태를 저장합니다.
상태는 favoriteMovies 이며, fetch, delFavoriteMovie, addFavoriteMovie 액션 함수를 통해 상태를 업데이트합니다.
이제 훅을 사용해보겠습니다. 처음 유저가 로그인 했을때 서버측(db)에 저장된 선호 영화 목록을 불러오기 위해 login 함수에 fetch 함수를 추가합니다.
login.tsx
"use client";
import { signIn } from "next-auth/react";
import { useRouter } from "next/navigation";
import { useState } from "react";
import style from "../_styles/login.module.css";
import useFavoriteMovies from "@/_hooks/useFavoriteMovies";
export default function Login() {
const router = useRouter();
const [id, setId] = useState("");
const [pw, setPw] = useState("");
const [isInvalid, setIsInvalid] = useState(false);
const { fetch } = useFavoriteMovies();
const handleSubmit = async (e: any) => {
e.preventDefault();
const res = await signIn("credentials", { id, pw, redirect: false }); // NextAuth의 signIn 함수를 사용하여 로그인 시도
if (res?.ok) {
router.push("/");
router.refresh();
fetch(id);
}
if (res?.status === 401) {
setIsInvalid(true);
}
};
return (
...
);
}
로그인이 성공했을 때, 초기 상태를 설정하기 위해 fetch 함수를 통해 선호 영화 목록을 가져옵니다.
로컬스토리지를 확인해보면 favoriteMovies-storage가 추가된 것을 확인할 수 있습니다.
이제 선호 영화를 추가해봅시다.
선호 영화 추가 버튼을 작성해줍니다
toggleLikeBtn.tsx
"use client";
import { useRouter } from "next/navigation";
import { addFavoriteMovie } from "../api/add-favorite-movie";
import { delFavoriteMovie } from "../api/del-favorite-movie";
import IconButton from "./ui/icon-button";
import { useSession } from "next-auth/react";
import useFavoriteMovies from "@/_hooks/useFavoriteMovies";
import { useEffect } from "react";
interface ILikeButtonProps {
movieID: string;
title: string;
postURL: string;
}
export default function ToggleLikeButton({ movieID, title, postURL }: ILikeButtonProps) {
const { data: session } = useSession();
const sessionId = session?.user?.name;
const { favoriteMovies, delFavoriteMovie, addFavoriteMovie } = useFavoriteMovies();
const router = useRouter();
// 영화가 선호 영화 목록에 있는 지 판단
const isMovieLiked = () => {
return favoriteMovies.some((movie: any) => movie.movie_id === movieID);
};
const toggoleLikeStatus = () => {
if (session === null) {
alert("로그인 후 이용 가능합니다.");
router.push("/login");
return;
}
const likeReqData = {
user_id: sessionId,
movie_id: movieID,
movie_title: title,
post_url: postURL,
};
const unLikeReqData = {
user_id: sessionId,
movie_id: movieID,
};
// 영화가 이미 선호 목록에 있으면 삭제, 아니면 추가 함수 실행
isMovieLiked() ? delFavoriteMovie(unLikeReqData) : addFavoriteMovie(likeReqData);
};
return (
<div>
<IconButton onClick={toggoleLikeStatus} icon={isMovieLiked() ? "❤️" : "🤍"} />
</div>
);
}
isMovieLiked 함수를 통해 이미 추가한 영화인지 판단하여 추가하거나 삭제할지 판단합니다.
영화를 추가시키면 로컬스토리지에 영화가 추가된 것을 확인할 수 있습니다.
이제 선호 영화 목록을 보여주는 화면을 작성합니다.
영화 목록 페이지
"use client";
import { useSession } from "next-auth/react";
import FavoriteMovies from "../../_components/user/favorite-movies";
import style from "../../_styles/user/page.module.css";
import useFavoriteMovies from "@/_hooks/useFavoriteMovies";
import { useRouter } from "next/navigation";
export default function User() {
const { favoriteMovies } = useFavoriteMovies();
return (
<div className={style.container}>
<h4>선호 영화 목록</h4>
<FavoriteMovies movies={favoriteMovies} />
</div>
);
}
결과 화면
이렇게 Zustand를 활용하여 선호 영화 목록 상태를 관리하는 법에 대해 알아보았습니다. Zustand를 통해 props drilling을 방지할 수 있었고, 간편하게 상태를 관리할 수 있었습니다.
'Next.js' 카테고리의 다른 글
[Next.js] Next.js에서 NextAuth 사용하기 (0) | 2024.03.02 |
---|---|
[Next.js] Next.js에서 zustand 사용하기 (1) | 2024.02.26 |
[Next.js] Next.js 14 revalidatePath (1) | 2024.02.24 |
[Next.js] Next.js 14 revalidateTag (0) | 2024.02.18 |
[Next.js] Next.js 14 Server Side Data Fetching (0) | 2024.02.17 |
- Total
- Today
- Yesterday
- React.JS
- revalidateTag
- dynamic routing
- rc-dock
- react-three-fiber
- useCallback
- NextAuth
- revalidatePath
- 25329
- 20551
- Next.js
- react-query
- web3
- js
- useState
- 24431
- RefreshToken
- 해시를 사용한 집합과 맵
- useQuery
- react.memo
- eventemitter3
- zustand
- baekjoon
- sepolia
- 4659
- React
- 백준
- useMemo
- 9575
- stompjs
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |