https://recoiljs.org/ko/docs/introduction/getting-started/
전역 상태 관리 라이브러리 Recoil
예를들어 header에서 받는 검색어 데이터를
다른 컴포넌트로 전달하고자 할 때
단반향으로 전달해야해서 계속 props로 타고 넘겨줘야하는 단점이 있다.
하지만 전역으로 상태를 관리하면 이 작업이 단순화돼서
모든 컴포넌트에 바로 데이터를 공유 할 수 있음
하지만 Recoil은 기본적으로 client 라이브러리임
별도의 프로바이더를 정의 해주고 적용한다.
npm install recoil
Atom: Recoil에서 atom은 상태의 단위입니다. atom은 우리가 읽고 쓸 수 있는 상태의 조각으로 생각할 수 있습니다. atom을 생성하려면, atom 함수를 사용하고 필요한 key와 default 값을 제공해야 합니다.
"use client";
import { RecoilRoot } from "recoil";
export default function RecoilProvider({ children }: React.PropsWithChildren) {
return <RecoilRoot>{children}</RecoilRoot>;
}
그리고 레이아웃에 적용한다.
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "config/material-tailwind-theme-provider";
import ReactQueryClientProvider from "config/ReactQueryClientProvider";
import Header from "components/header";
import Footer from "components/footer";
import RecoilProvider from "config/RecoilProvider";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
{/* @ts-ignore */}
<head>
<link
rel="stylesheet"
// 폰트어썸 라이브러리 동작할 수 있게끔 추가한거임
integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w=="
crossOrigin="anonymous"
referrerPolicy="no-referrer"
/>
</head>
<body className={inter.className}>
<RecoilProvider>
<ReactQueryClientProvider>
<ThemeProvider>
<Header />
{children}
<Footer />
</ThemeProvider>
</ReactQueryClientProvider>
</RecoilProvider>
</body>
</html>
);
}
import { atom } from "recoil";
export const searchState = atom({
key: "searchState",
default: "",
});
그 뒤 Header 컴포넌트에서
useRecoilState를 사용해서 (useState와 동일한 기능)
searchState에 검색어를 저장한다.
input에 onchange 이벤트가 일어나면 그 검색어를 전역으로 상태 관리함
"use client";
import { useRecoilState } from "recoil";
import Logo from "./logo";
import { searchState } from "utils/recoil/atoms";
export default function Header() {
const [search, setSearch] = useRecoilState(searchState);
return (
<header className="fixed top-0 left-0 right-0 px-4 py-2 bg-gray-900 flex items-center justify-between z-50">
<nav className="flex gap-4">
<Logo />
<ul className="flex gap-2 text-white">
<li>Movies</li>
<li>Drams</li>
</ul>
</nav>
<div className="flex gap-2 w-full max-w-72 items-center border border-white rounded-md p-2 bg-transparent text-white">
<i className="fas fa-search" />
<input
className="bg-transparent "
placeholder="Search Movies"
onChange={(e) => setSearch(e.target.value)}
/>
</div>
</header>
);
}
그리고
useRecoilValue를 사용해서 ( 읽기만 가능 ) 검색어 데이터를 가져와서
useQuery 의 searchMovies 함수에 전달해주면됨
"use client";
import { useQuery } from "@tanstack/react-query";
import MovieCard from "./movie-card";
import { searchMovies } from "actions/movieActions";
import { Spinner } from "@material-tailwind/react";
import { useRecoilValue } from "recoil";
import { searchState } from "utils/recoil/atoms";
export default function MovieCardList() {
const search = useRecoilValue(searchState);
const getAllMoviesQuery = useQuery({
queryKey: ["movie", search],
queryFn: () => searchMovies(search),
});
return (
<div className="grid gap-1 grid-cols-3 md:grid-cols-4 w-full h-full">
{getAllMoviesQuery.isLoading && <Spinner />}
{getAllMoviesQuery.data &&
getAllMoviesQuery.data.map((movie) => (
<MovieCard key={movie.id} movie={movie} />
))}
</div>
);
}
'FRONTEND > Next.js' 카테고리의 다른 글
[Next.js 14 + Supabase ] Supabase auth 로그인 처리 및 6Digit OTP 방식 회원가입 (0) | 2024.08.14 |
---|---|
[Next.js 14 + Supabase ] Supabase auth로 이메일 인증 처리 및 회원가입 처리하기 (0) | 2024.08.12 |
[Next.js 14 + Supabase ] Supabase Storage 파일 업로드 구현 및 react-dropzone 라이브러리 활용 (0) | 2024.08.01 |
[Next.js 14 + Supabase ] 할 일 CRUD 기능 구현 (0) | 2024.07.29 |
[Next.js 14 + Supabase ] Supabase 프로젝트 생성 (0) | 2024.07.27 |