์ฝ๋๋ฅผ ์ผ์ผ์ด ์ ๋ ฅํ์ง ์๊ณ ์ด ํด๋๋ค์์ ๋ง์ด ๋ณต์ฌํด์ต๋๋ค. ์ผ์ผ์ด ์ ๋ ฅํ ์๊ฐ ์๋๊ฒ, svg ๊ฐ์ ํ๊ทธ๋ ์๊ณ css๋ ๋๋ฌด ๋ง์ต๋๋ค. ์ ๊ฐ ๋ญ๊ฐ๋ฅผ ๋ณต์ฌํ๋ค๊ณ ํ๋ฉด ์ฌ๋ฌ๋ถ๋ค๋ ์ฌ๊ธฐ์ ๋ณต์ฌํด์ค์ธ์.
๊ธฐ์กด ์ ๋ค๋ฅธ ํด๋ก ์ฝ๋ฉ ๊ฐ์ข๋ฅผ ์๊ฐํ๊ณ ๋ฐ๋ผ์น๊ธฐ ์ํด ๋ค์ผ์๋ฉด ์ ๋ฉ๋๋ค. ์ผ๋ก๋ก ๋ฆฌ์กํธ ๋ ธ๋๋ฒ๋ ๊ฐ์๋ณด๋ค ์ฝ๋๋์ด 3๋ฐฐ ์ ๋ ๋ ๋ง์์ ๋ฐ๋ผ์น๊ธฐ๋ณด๋ค๋ ๋ณต์ฌํ๋ฉด์ ์ค๋ช ํ๋ ๋ฐฉ์์ ์ทจํ์ต๋๋ค.
ch0 ํด๋์์๋ถํฐ ์์ํ์๋ ๊ฒ์ ๊ฐ๋ ฅํ ์ถ์ฒ๋๋ฆฝ๋๋ค.
- ch0: ์ด๊ธฐ ์ธํ ("css module์ ์ ํํ ์ด์ " ๊ฐ์๊ฐ ๋๋ฌ์ ๋์ ์ฝ๋ - ์ด ํด๋๋ฅผ ๋ณต์ฌํด์ ์์ํ์๋ฉด ํธํฉ๋๋ค)
- ch1: ์น์ 1์ด ์๋ฃ๋ ์ฝ๋
- ch2-1: ์น์ 2์ "classnames๋ก ํด๋์ค ํฉ์ฑํ๊ธฐ"๊น์ง์ ์์ค ์ฝ๋
- ch2-2: ์น์ 2๊ฐ ์๋ฃ๋ ์์ค ์ฝ๋
- ch3-1: ์น์ 3์ next-auth๊ฐ ์ ์ฉ๋ ์์ค ์ฝ๋
- ch3-2: ์น์ 3์ react query ์ธํผ๋ํธ ์คํฌ๋กค๋ง์ด ์ ์ฉ๋ ์์ค ์ฝ๋
- ch4: ๋ฐฐํฌ ์ง์ ์์ค ์ฝ๋(ํฌํธ 80์ผ๋ก ๋ฐ๊พธ๊ธฐ ์ )
- lecture: ๊ฐ์ ์์ฑ๋ณธ ์ฝ๋(๋ฒ๊ทธ๊ฐ ์ข ์์ต๋๋ค. ๋ฒ๊ทธ ํด๊ฒฐ์ ์๋ z-com ๋ ํฌ์งํ ๋ฆฌ์์ ๊พธ์คํ ํ๊ณ ์์ด์.)
- z-com: z.nodebird.com ๋ฐฐํฌ ์์ค ์ฝ๋(๋ต๊ธ, ์ฌ๊ฒ์, ์ค์๊ฐ ์ฑํ ๋ฑ๋ฑ์ด ์์ฑ๋์ด ์์ด์!)
์ ๋ณด๋ค ๋ ์ ๋ฆฌ๋ฅผ ์ ํด๋์ ๋ถ๋ค์ ๋ ธํธ์ ๋๋ค. ๊ฐ์ด ๋ณด์๋ฉด์ ๊ณต๋ถํ์๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค. ์๊ฐ์ ๋ฒ ์คํธ ๊ฐ์๋ ธํธ ๋งํฌ
๊ฐ์ฅ ํฌ๊ฒ ๋ค๋ฅธ ์
- ๊ฐ์ข ํด๋ ์ ํ ์ถ๊ฐ๋ก ๋๋ ํ ๋ฆฌ ๋ผ์ฐํ ์ด ํธํด์ง
- ๋ ์ด์์ ๊ธฐ๋ฅ
- ํ์ด์ง๋ณ ๊ถํ ์ฒดํฌ
- ์๋ฒ ์ปดํฌ๋ํธ ๋ถ๋ฆฌ๋ก ์ธํ ์ต์ ํ
- ๋ฐ์ดํฐ ์บ์
- ์๋ฒ ์ก์
- ํฌํธํด๋ฆฌ์ค๋ก ์ฌ์ฉ ๊ธ์ง(์๊ฐ์๋ค์ด ๊ฐ์ ๊ฑธ ๋ง์ด ์ ์ถํด์ ๋์น์ฑ)
- ๋ ๋นผ๊ณ ๋ฐ๋ผ๋ง ํ๋ ๊ฒฝ์ฐ๋ ์ค๋ ฅ์ด ์ ํ ๋์ง ์์ โ ์ค์ค๋ก ํด๋ณผ ๊ฒ
- HTML, CSS๋ฅผ ๊ฐ๋ฐ์๋๊ตฌ๋ฅผ ํตํด ๊ณต๋ถํ ์ ์๊ณ , HTTP ์์ฒญ๋ ๋คํธ์ํฌ ํญ์ ํตํด ๋ถ์ํด๋ณผ ์ ์์.
- ์์ด๋์ด๊ฐ ์ ๋ ์ค๋ฅผ ๋ ์ข์ ๋ฐฉ๋ฒ์. ๋ณดํต์ ์ฐ๋ ๊ธฐ๋ฅ๋ง ๊ณจ๋ผ์ ์ฐ๋๋ฐ ํด๋ก ์ฝ๋ฉ์ ํ๋ค๋ณด๋ฉด ์ฒ์ ๋ณด๋ ๊ธฐ๋ฅ์ ๊ตฌํํ๊ธฐ ์ํด ์จ๊ฐ ์๋๋ฅผ ํด๋ณด๊ฒ ๋จ โ ๊ณต์๋ฌธ์๋ฅผ ์์ธํ๊ฒ ์ฝ๊ฒ ๋จ
์ฒ์์ ์ง์ ์ธํ ํ๊ธฐ๋ณด๋จ ch0 ํด๋ ๋ด๋ถ ๋ด์ฉ์ ๋ณต์ฌํด์ ์์ํ์๋ฉด ํธํฉ๋๋ค.
์์ ์ฒ์๋ถํฐ ์ธํ ํ์๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด...
- ํ๋ก์ ํธ ํด๋๋ฅผ ๋ง๋ค๊ณ ์ถ์ ๊ณณ์ผ๋ก ๊ฐ์
npx create-next-app@latest
- ๊ฐ์์ ๊ฐ๊ฒ ์ ํํ๊ธฐ
- [username]์ ์ฌ์ฉ์ ํ๋กํ
- i/flow/signup, i/flow/login์ด๋ compose/tweet์ ํ์ด์ง ์ ํ ์์ด ๋ชจ๋ฌ ๋์์ผ ํจ
- ๋ก๊ทธ์ธ ํ์๋ /home์ผ๋ก redirect
- /login๋ /i/flow/login์ผ๋ก redirect
- ์ด๋ฆ์ ๊ณ ์ ์(๋ฐ๊ฟ ์ ์์)
- layout.tsx์ template.tsx๋ ๊ณต์กดํ ์ ์์
- page.tsx๋ layout.tsx์ ์์์ผ๋ก ๋ค์ด๊ฐ
- (afterLogin), (beforeLogin) ํด๋๋ ์ค์ ๋ก ๊ฒฝ๋ก์ ๋ฐ์๋์ง๋ ์์
- ํ์ ํด๋๋ค์ layout ์ ์ฉ ์ฉ๋
- vanilla-extract๋ฅผ ์ฌ์ฉํ๋ ค ํ์ผ๋ Windows์์ Server Component ์ง์ํ์ง ์์ ๋งํฌ
- WSL์ ์ฐ๋ฉด ๋๋ Hot reloading์ด ๋ฌธ์ ๊ฐ ์๊น
- ์ถํ ์ด ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋๋ฉด vanilla-extract ๋์ ์์ (๋ณด๋์ค ๊ฐ์์์ ๋ค๋ฃน๋๋ค!)
const segment = useSelectedLayoutSegment();
- layout์์๋ง ์ฌ์ฉ ๊ฐ๋ฅ, page์์๋ ์ฌ์ฉ ๋ถ๊ฐ(usePathname ์ฌ์ฉํ ๊ฒ)
- ๋ฐ๋ก ํ์๋ง ๋์ด(compose/tweet์ ๊ฒฝ์ฐ compose๋ง ๋์ด)
- ๋ชจ๋ depth๋ฅผ ๊ฐ์ ธ์ค๊ณ ์ถ๋ค๋ฉด useSelectedLayoutSegments (['compose', 'tweet'])
- layout์ state๋ ๋ชจ๋ ํ์ด์ง์ ๊ณต์ ๋จ
- ๊ณต์ ํ๊ธฐ ์ซ๋ค๋ฉด layout ๋์ template.tsx ์ฐ๊ธฐ(๋งค๋ฒ ์๋ก ๋ ๋๋ง ๋จ)
i/flow/signup๊ณผ i/flow/login์ ์ด๊ฑธ๋ก ์ฒ๋ฆฌ
- @ ํด๋ ์์ default.tsx ์์ง ๋ง๊ธฐ
- (beforeLogin) ๋ด๋ถ์ @modal ์์ (.)/flow/signup์ ๋ง๋ค์ด์ผ ํจ
- (beforeLogin)๊ณผ ๋๋ฑ ๋ ๋ฒจ์ ๋ง๋๋ ๊ฒฝ์ฐ The default export is not a React Component in page ์๋ฌ ๋ฐ์
- /login์์ /i/flow/login์ผ๋ก ๊ฐ๊ธฐ ์ํด์๋ redirect๋ก๋ ์ ๋๊ณ , router.replace๋ฅผ ํด์ผ ํจ. "use client" ์ฌ์ฉ ํ์.
๋ค์ ์๋ฌ๊ฐ ๋๋ ๋ถ๋ถ์ ๋ถ๋ฆฌํ์(Client Component๋ก ๋ถ๋ฆฌ ํ importํ๋ฉด ๋จ)
Error: usePathname only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component
at RootLayout (./src/app/layout.tsx:29:86)
at stringify (<anonymous>)
-
NavIcons๋ก ์์ด์ฝ๋ค ๋ถ๋ฆฌ
-
_components ํด๋์ ์ฃผ๋ก Client Component ์์ฑ
-
useState, useRef, useEffect, useContext, useRouter, useSearchParams, onClick ๋ฑ๋ฑ ๋ง๋ค
-
ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ ์๋ฒ์ชฝ์์ ๋ ๋๋ง ๋จ, ์ฆ SSR ๋์
-
์๋ฒ ์ปดํฌ๋ํธ๋ ์๋ฒ"์์๋ง" ๋ ๋๋ง ๋จ
compose/tweet๋ ์ด๊ฑธ๋ก ์ฒ๋ฆฌ
- @modal/compose/tweet์ผ๋ก ๋ฐ๊พธ๊ณ parallel router ์ ์ฉ
- @modal์ด๋ผ๋ slot ์ฌ์ฉํ๋ฉด props.modal๋ก ์ ๊ทผ ๊ฐ๋ฅ
- parallel router ์ ์ฉ ์ default.tsx ๊ผญ ๋ฃ์ด์ฃผ์ด์ผ ํจ!!! ์๋ก๊ณ ์นจํ ๋ ์ฃผ์ํ ๊ฒ!!!
- ์๋ก๊ณ ์นจ ์์๋ ๋ฐฑ๊ทธ๋ผ์ด๋๋ home์ด ๋ณด์ฌ์ผ ํจ
- compose/tweet ํด๋ ํ ๋ฒ ๋ ๋ง๋ค์ด์ฃผ๊ธฐ
- home ํด๋ ์์ @modal์ app/(afterLogin)/layout.tsx์์ ์ธ์๋์ง ์์์ ์ฌ์ฉ ๋ถ๊ฐ
- layout.tsx์ ๊ฐ์ ์์น์ธ app/(afterLogin) ์์ @modal์ ๋ฃ์ด์ผ ํจ
- faker.js๋ ๋๋ฏธ๋ฐ์ดํฐ ์์ฑ์ฉ
- npm i fakerํ์ง ์๋๋ก ์ฃผ์
npm i -D @faker-js/faker
- ์ฉ๋์ด ํฌ๋ฏ๋ก ๋ฐฐํฌ ์์๋ ์ ๊ฑฐํด์ผ ์ฉ๋์ ์ค์ผ ์ ์์
- Client Component์์ Server Component importํ๋ฉด ์ ๋จ, importํ๋ฉด Server Component๋ Client Component์ฒ๋ผ ์ทจ๊ธ๋จ
- props(children์ด๋ ๊ธฐํ props)๋ก ๋๊ธธ ๊ฒ
npm install msw -D
npx msw init public/ --save
- ์ค์ ๋ฐฑ์๋ ์๋ฒ๋ก ๋ณด๋ด๋ ์์ฒญ์ ๊ฐ๋ก์ฑ ์ ์์
- ํ๋ก ํธ ๊ฐ๋ฐ์๊ฐ ์์๋ก ์๋ต์ ๋ง๋ค์ด๋ผ ์ ์์(์ฑ๊ณต, 400, 500 ์๋ฌ ๋ชจ๋ ๊ฐ๋ฅ)
ํด๋น ์ด์๋ก msw ์๋ฒ์์ ์ฌ์ฉ ๋ถ๊ฐ
- ์ ์ด์ ํด๊ฒฐ๋๊ธฐ ์ ๊น์ง๋ http ์๋ฒ ์ง์ ์์ฑ
- ํ์๊ฐ์ ์ ์ ์ฉํ๊ธฐ(Next 14๋ถํฐ ๊ฐ๋ฅ)
- ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์๋ server action ํจ์๋ฅผ import ํด์ ์ฌ์ฉ ๊ฐ๋ฅ
- ํผ ๊ฒ์ฌ๋ฅผ ์ํด useFormState์ useFormStatus ์ ์ฉํ๊ธฐ
npm install next-auth@5 @auth/core
- next-auth@5๊ฐ ์ค์น๊ฐ ์ ๋๋ฉด next-auth@beta๋ฅผ ๋์ ์ค์น
- auth.ts, middleware.ts, app/api/auth/[...nextauth]/route.ts ์์ฑ
- ๋ก๊ทธ์ธ์ ์ํด signIn("credentials") ํธ์ถ(csrf ํ ํฐ ์์์ ๊ด๋ฆฌ), 5.0.0-beta.4์์๋ ๋ฒ๊ทธ ์์ผ๋ ์ฃผ์!
- ๋ก๊ทธ์์์ ์ํด signOut ํธ์ถ
- ํด๋ผ์ด์ธํธ์์ ๋ด ์ ๋ณด ๊ฐ์ ธ์ฌ ๋๋ useSession(), ์๋ฒ์์๋ await auth();
- session ์ ๋ด ์ ๋ณด๋ email, name, image๋ง ๊ฐ๋ฅ(ํท๊ฐ๋ฆฌ๋ ์ฃผ์)
middleware.ts๋ก ํ์ด์ง ์ ๊ทผ ์ ์ด
- (afterLogin) ๋ด๋ถ์ [username]๊ณผ [username]/status/[id] ํ์ด์ง๋ ๋ชจ๋ ๊ณต๊ฐ
- ๊ทธ ์ธ (afterLogin) ํ์ด์ง๋ค์ ๋ก๊ทธ์ธํ ์ฌ๋๋ง ์ ๊ทผ ๊ฐ๋ฅ
npm i @tanstack/react-query @tanstack/react-query-devtools
- ํ์ ์ ๋ง์ถ๊ธฐ(QueryFunction, QueryKey)
- ๋งํฌ
- ์ฟผ๋ฆฌ ํค ์ ๋ฆฌ(๋๋ถ๋ฅ-์ค๋ถ๋ฅ-์๋ถ๋ฅ)
- SSR(HydrationBoundary, prefetchQuery)
- ์๋ฒ์ฌ์ด๋์์๋ prefetchInfiniteQuery๋ก ๋ณ๊ฒฝ
- ์ปค์ ๋ฐฉ์์ ๋ํ ์ดํด
npm install react-intersection-observer
- connect.sid๋ ๋ฐฑ์๋ ์๋ฒ์ฉ ์ฟ ํค
- authjs.session-token(๊ตฌ next-auth.session-token)์ ํ๋ก ํธ ์๋ฒ์ฉ ์ฟ ํค
- ์ฟ ํค๋ฅผ ์ ์กํ๋ ค๋ฉด credentials: 'include' ํ์
- ํ๋ก ํธ ์๋ฒ์์ ๋ฐฑ์๋ ์๋ฒ๋ก ์ฟ ํค๋ฅผ ์ ์กํ๋ ค๋ฉด headers: { Cookie: cookies().toString() } ํ์
์บ์ํ ๋ฐ์ดํฐ ์ข ๋ฅ ๊ตฌ๋ถํ๊ธฐ
- Request Memo(๋ ๋๋ง ์ GET Request ์ ๊ฐ์ ์ฃผ์ fetch๋ฉด ํ ๋ฒ๋ง ์์ฒญํด์ ๊ฐ์ ธ์ด, route.js์์๋ ์ ๋จ)
- Data Cache(ํ ๋ฒ fetchํ ๊ฒ์ ์๋ฒ๊ฐ ๊ธฐ์ตํด๋๊ณ ์๋ค๊ฐ ๋ค์ ์์ฒญ ๋ ์ฌ์ฌ์ฉ)
- Full Route Cache: ํ์ด์ง ์ ์ฒด๋ฅผ ์บ์ฑํ๋ ๊ฒ(static page๋ง ๊ฐ๋ฅ, page router์ ISR์ ๋์ฒด)
- Router Cache: ํด๋ผ์ด์ธํธ์์ layout, page๋ณ๋ก ๋ฐ๋ก ์บ์ฑํด๋๋ ๊ฒ
- Static vs Dynamic rendering: Dynamic function์ ์ฐ๋๊ฐ vs Cache๋ฅผ ์ฐ๋๊ฐ
- dynamic function์ ์ฐ์ง ์๊ณ cache๋ฅผ ํ์ฉํ๋ฉด static ํ์ด์ง
"use client" ์๋์์๋ง ์ฌ์ฉ ๊ฐ๋ฅ
- context api ๋๋น ์ต์ ํ๊ฐ ๊ธฐ๋ณธ ์ ์ฉ๋์ด ์์ด์ ์ ๊ฒฝ์ธ ๊ฒ ์๋ค.
- client component์์๋ async component ๋ถ๊ฐ๋ฅ
- ๋์ ํ ์๋ก๊ณ ์นจ ํ ๋ฒ์ฉ ํด๋ณผ ๊ฒ
npm i @vanilla-extract/css @vanilla-extract/next-plugin
next.config.js
const {
createVanillaExtractPlugin
} = require('@vanilla-extract/next-plugin');
const withVanillaExtract = createVanillaExtractPlugin();
...
module.exports = withVanillaExtract(nextConfig);
- app/globals.css๋ฅผ app/globalTheme.css.ts๋ก ๋์ฒด
- :root์ @media (prefers-color-scheme: dark)๋ฅผ ์ ์ฉํ๋ ค๋ฉด ์กฐ๊ธ ๋ณต์กํจ
- (beforeLogin)/_component ๋ด๋ถ css.ts ํ์ผ๋ค์ด VE ํ์ผ๋ค์
- globalStyle ํจ์๋ฅผ ๋ณด๋ฉด ์๊ฒ ์ง๋ง, nested selector๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ญ๊ฐ ๋ถ์์ฐ์ค๋ฌ์
- npm run build๋ก ๊ฒฐ๊ณผ ํ์ผ ์์ฑ
- ๋น๋ ์ ์ฉ๋ ์ ํ์ธํ๊ธฐ
- .env, .env.production ๊ฐ ์ค์ ์๋ฒ ๊ฐ์ผ๋ก ์์ ํ๊ธฐ
- ์๋ฒ์์ npm run start๋ก ์คํํ๋ฉด ๋จ