npm install
npm run dev
๊ฑฐ์๋ค use client
๋ก ์ ์ธํ์ฌ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ๋ง๋ค์๋ค. onClick, useState๋ฑ์ด ์์ผ๋ฉด ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ๋ง๋๋๊ฑด ์๊ฒ ๋๋ฐ ๊ทธ๊ฑฐ ์๋ ๊ฒ๋ค์ ์ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ๋ง๋ค๊น?
Modal์ ์ํ๋ ์ปค์คํ
ํ
+ zustand์ ์ ์ญ ์ํ ๊ด๋ฆฌ๋ก ์ด์๋ค ๋ซ์๋ค๋ฅผ ํ๋ค. ์๋ํ๋ฉด ์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ๋ชจ๋ฌ์ด ์ด๋ฆฌ๋ ๊ฒ์ ํธ๋ค๋ง ํด์ผํ๊ธฐ ๋๋ฌธ์ด๋ค.
์์์ฝ๋ : ์ปค์คํ ํ + zustand
import { create } from 'zustand';
interface RegisterModalStore {
isOpen: boolean;
onOpen: () => void;
onClose: () => void;
}
const useRegisterModal = create<RegisterModalStore>((set) => ({
isOpen: true,
onOpen: () => set({ isOpen: true }),
onClose: () => set({ isOpen: false }),
}));
export default useRegisterModal;
return (
<html lang='en'>
<body className={font.className}>
<ClientOnly>
<ToasterProvider />
<RegisterModal />
{/* <Modal actionLabel='Submit' title='hello world' isOpen={true} /> */}
<NavBar />
</ClientOnly>
{children}
</body>
</html>
ClientOnly
๋ํผ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด์ ํ์ด๋๋ ์ด์ ์๋ฌ๊ฐ ๋์ง ์๊ฒํ๋ค. ์ค์ง ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์๋ง ๋๋๋งreact-hot-toast
๋ฅผ ์ค์นํด์ClientOnly
๋ํผ ์ปดํฌ๋ํธ์์์ Provider๋ก ์ ์ธํ์ฌ ์ฌ์ฉํ๊ณ ์๋ค.
npm install -D prisma
npx prisma init
- Prisma๋ฅผ ์ฌ์ฉํด์ DB Schema๋ฅผ ๋ง๋ ๋ค. (/prisma/schema.prisma ์ฐธ๊ณ )
- next-auth๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์ ์ด์ฉ์ ์์ด
pages ๋๋ ํ ๋ฆฌ
๋ฅผ ๋ง๋ ๋ค. (์ฌ์ฉํ๊ธฐ ์ํด ์ด์ฉ ์ ์์์) /page/api/auth/[...nextauth].ts
์ next-auth ๊ด๋ จ ๋ก์ง์ ๋ฃ์ด์ค๋ค. (์ด๊ฒ ๋ณต์กํจ.... ๐ฅฒ)- /app/api/register/route.ts์ POST์์ฒญ์ธ ํ์๊ฐ์ ๋ก์ง์ ๋ฃ๋๋ค (DB์ ์ ๊ท ์ ์ ์์ฑ with prisma), ์ค์ ํ์๊ฐ์ API๋ฅผ ๋ง๋๋ ๊ณผ์ .
Signup
๊ณผ๋ ๋ค๋ฅด๊ฒLogin
์credentials
๋ผ๋ ๊ฒ์ ์ฌ์ฉ([...nextauth]์ ์ ์ธ๋์ด์๋)ํด์ ๋ก๊ทธ์ธ ๋ก์ง ๋ฐ onSumbitํธ๋ค๋ฌ๋ฅผ ์์ฑํ๋ค.- ServerComponent์ ํน์ฑ์ ์ด์ฉํ์ฌ ๋ก๊ทธ์ธ ํ ์ ์ ์ ๋ณด๋ฅผ DB์์ ๋ค์ด๋ ํธ๋ก ๊ฐ์ ธ์จ๋ค. (์๋ฒ ์ปดํฌ๋ํธ์ด๋๊น ๊ฐ๋ฅํ์ !!) ์ด๋ ๊ฒ ๋๋ฉด API ์ฝ์ ์ํด๋๋๋ค๋ ์ด์ ์ด ์๋ค!!
- ์๋ฒ ์ปดํฌ๋ํธ์์ ๊ฐ์ ธ์จ
currentUser
๋ฅผ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์ props๋ก ๋๊ฒจ์ค๋ค! ๐ฅฐ - ๊ฐ์ ธ์จ ์ ์ ์ ๋ณด๋ก ๋ก๊ทธ์ธ์ ๋ณด์ฌ์ค ๋ฉ๋ด๋ค์ ์กฐ๊ฑด๋ถ ๋ ๋๋ง ํ์ฌ ๋ณด์ฌ์ค ์ ์๋ค.
- ๋ก๊ทธ์์์
next-auth
์ signOut ํจ์๋ง ํธ์ถํ๋ฉด ์๋์ผ๋ก ๋ก๊ทธ์์์ด ๋๋ค. (์์ฒญ ํธํจ.)
- ์นดํ
๊ณ ๋ฆฌ ๋ฒํผ(beach, windMills, Modern)์ ํด๋ฆญํ์๋, url ์ฐฝ์
url?category='๋ญ์๊ธฐ'
์ด๋ฐ์์ผ๋ก ํ์ด์ง๊ฐ ์ด๋(`router.push`` ์ฌ์ฉ)๋๋ก ๋ง๋ ๋ค. - ํด๋น ์นดํ ๊ณ ๋ฆฌ ๋ฒํผ์ ํ๋ฒ ๋ ๋๋ฅด๊ฒ ๋๋ฉด query String์ ์ง์ด๋ค.
- ์นดํ
๊ณ ๋ฆฌ ๋ฒํผ์
label
๊ณผ url queryString์ category๊ฐ๊ณผ ๊ฐ์์ง ๋น๊ตํด์ props๋ก ๋๊ธฐ๋ ๋ฐฉ์
1๋ฒ, 3๋ฒ ๊ตฌํ
const handleClick = useCallback(() => {
let currentQuery = {};
if (params) {
currentQuery = qs.parse(params.toString());
}
console.log('ํ์ฌ ์ฟผ๋ฆฌ', currentQuery);
const updateQuery: any = {
...currentQuery,
category: label,
};
// ํ์ฌ ์ฟผ๋ฆฌ ์คํธ๋ง์ category ๊ฐ๊ณผ ๋๋ฅธ label์ด ๊ฐ์ผ๋ฉด ์ฟผ๋ฆฌ ์ญ์
if (params?.get('category') === label) {
delete updateQuery.category;
}
// ์ค์ ๋ก ์ด๋์ํฌ ์ฟผ๋ฆฌ ์์ฑ
const url = qs.stringifyUrl(
{
url: '/',
query: updateQuery,
},
{ skipNull: true }
);
// ์ค์ ๋ก ์ด๋์ํด
router.push(url);
}, [label, params, router]);
- ์ปจ์ ์ ์ฐ๋ฆฌ๊ฐ ํ์๊ฐ์ ํ๋ ํ๋ฉด์ฒ๋ผ step1 ~ step6 ๊น์ง ๋๊ธฐ๋ฉด์ ๋ง์ง๋ง์ ์ ์ถํ๋ ๋ฐฉ์
- step1 ~ step6๊น์ง์ ํ๋ฉด์ด ๋ฐ๋๊ฒ ํ๋๊ฒ์ bodyContent๋ฅผ let์ผ๋ก ์ ์ธํ ํ ์ฌํ ๋น ํ๋ ๋ฐฉ์์ผ๋ก ํ๋ฉด์ ๋ณ๊ฒฝํด์ค + Enum
enum STEPS {
CATEGORY = 0,
LOCATION = 1,
INFO = 2,
IMAGES = 3,
DESCRIPTION = 4,
PRICE = 5,
}
- form์ state๋ react-hook-form์ ์ฌ์ฉํ๋ค.
- Step1์
<CategoryInput/>
์ map์ ์ด์ฉํ์ฌ, ๋ฆฌ์คํ ํด์ค๋ค. ์ฌ๊ธฐ์ react-hook-form ์ฌ์ฉ๋ฒ์ ์ตํ์ผํ ๋ฏ ํ๋ค. - Step2๋
react-select
์world-countries
๋ฅผ ์ฌ์ฉํ์ฌ, ์ ์ธ๊ณ ๋๋ผ๋ค์ select ui๋ก ๋ณด์ฌ์ค๋ค. useCountries
๋ผ๋ ์ปค์คํ ํ ์ ๋ง๋ค์ด, ํด๋น ๋๋ผ๋ค์ ๊ฐ์ ธ์ค๋ Select UI๋ฅผ ๋ง๋ฌ
์์์ฝ๋)
import countries from 'world-countries';
const formattedCountries = countries.map((country) => ({
value: country.cca2,
label: country.name.common,
flag: country.flag,
latlng: country.latlng,
region: country.region,
}));
const useCountries = () => {
const getAll = () => formattedCountries;
const getByValue = (value: string) => {
return formattedCountries.find((item) => item.value === value);
};
return {
getAll,
getByValue,
};
};
export default useCountries;
โญ๏ธ ์ ์ผ ์ค์ํ๊ฑด react-hook-form์ผ๋ก form ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๊ณ , ๋ค๋ก๊ฐ๋ค ์์ผ๋ก ๊ฐ๋คํ๋๋ผ๋ state๊ฐ ์ ์ง๋๋๊ฒ!
- ์ง๋๋ฅผ next.js์ dynamic import๋ก ๊ฐ์ ธ์ค๋๊ฒ ์ ์ํ ์ฌํญ!
npm install query-string
npm install leaflet
npm install @types/leaflet
npm install react-leaflet
npm install world-countries
npm install react-select