2024-03-26.md

๐Ÿก

DIL: ๋ชจ๋˜ ๋ฆฌ์•กํŠธ ๋”ฅ ๋‹ค์ด๋ธŒ, 4์ฃผ์ฐจ-2

์Šคํ„ฐ๋””: ์›”๊ฐ„ CS, https://github.com/monthly-cs/2024-03-modern-react-deep-dive
์˜ค๋Š˜ ์ง„ํ–‰: ๊ฐœ์ธ๊ณต๋ถ€


DIL-week4-2_2024-03-26

| DIL ์ฃผ์ฐจ | ๋ฒ”์œ„ | ๋‚ด์šฉ | ์˜ค๋Š˜์ฐจ ์ง„๋„ | | -------- | ------ | ------------------------------- | ----------- | | 4์ฃผ์ฐจ | 4, 8์žฅ | SSR๊ณผ ESlint, ํ…Œ์ŠคํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ | 293p~310p |

์˜ค๋Š˜ ์ฝ์€ ๋‚ด์šฉ์„ markdown์œผ๋กœ ๊ฐ„๋‹จํžˆ ๋ฉ”๋ชจ
์ฝ์€ ์‹œ๊ฐ„: 9์‹œ30๋ถ„~11์‹œ


Next.js ํ†บ์•„๋ณด๊ธฐ

Next.js

  • ์—ญ์‚ฌ
    • PHP ๋Œ€์šฉํ’ˆ์œผ๋กœ ์œ„ํ•ด ๋งŒ๋“ค์—ˆ์—ˆ์Œ, SSR
    • ๋‹น์‹œ ํŽ˜์ด์Šค๋ถ์ด ๊ณ ๋ คํ•˜๋˜ SSR -> react-page
  • Vercel
    • SWR, SWC, Turbopack, Svelte ๋“ฑ ์˜ํ–ฅ๋ ฅ ์žˆ๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐœ๋ฐœ ๋ฐ ์ธ์ˆ˜
  • eslint-config-next: ๊ตฌ๊ธ€๊ณผ ํ˜‘์—…ํ•ด ๋งŒ๋“  ์›น ์ง€ํ‘œ (core web vital)์— ๋„์›€์ด ๋˜๋Š” ์ง€ํ‘œ
  • next.config.js
    • reactStrictMode: ๋ฆฌ์•กํŠธ ์—„๊ฒฉ ๋ชจ๋“œ
    • swcMinify:
      • SWC ๋ฒˆ๋“ค๋ง & ์ปดํŒŒ์ผ (๋ฐ”๋ฒจ ๋Œ€์šฉ)
      • ๋น ๋ฅด๋‹ค (Rust, ๋Ÿฌ์ŠคํŠธ๋Š” C/C++ ๋งŒํผ ๋น ๋ฆ„ + ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ)

Next13 page ๋ผ์šฐํŒ…

pages/_app.tsx

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด ํŽ˜์ด์ง€์˜ ์‹œ์ž‘์ 
    • ์›น ์•ฑ ๊ณตํ†ต ์„ค์ • ex) ์—๋Ÿฌ ๋ฐ”์šด๋”๋ฆฌ, reset.css, ์ „์—ญ ๋ฐ์ดํ„ฐ ์ œ๊ณต ๋“ฑ
  • ๋žœ๋”๋ง ์œ„์น˜
    • app์—์„œ console.log์„ ์ฐ์–ด๋ณด๋ฉด? => Next.js๋ฅผ ์‹คํ–‰ํ•œ ํ„ฐ๋ฏธ๋„์— ๊ธฐ๋ก
    • ํŽ˜์ด์ง€๋ฅผ ์ „ํ™˜ํ•˜๋ฉด? => ๋ธŒ๋ผ์šฐ์ €์— ๋กœ๊น…
    • ์ฆ‰, ์ตœ์ดˆ์—๋Š” ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋žœ๋”๋ง, ์ดํ›„์—๋Š” app.tsx์˜ ๋žœ๋”๋ง ์‹คํ–‰

pages/_document.tsx

  • DOM ์š”์†Œ
  • hydrate ๋˜๊ธฐ ์ „ ์ƒํƒœ
  • Next 13, ๋‘ ๊ฐ€์ง€ head
    • next/document์˜ head(DOM), next/head(SEO metadata)
  • CSS-in-JS ์Šคํƒ€์ผ์„ ์„œ๋ฒ„์—์„œ ๋ชจ์•„ HTML๋กœ ์ œ๊ณตํ•œ๋‹ค

| ๊ตฌ๋ถ„ | ๋žœ๋”๋ง ์œ„์น˜ | ๊ธฐ๋Šฅ | | ------------- | ----------------- | ------------- | | _app.tsx | ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ | Next๋ฅผ ์ดˆ๊ธฐํ™” | | _documet.tsx | ์„œ๋ฒ„ | HTML ์„ค์ • |

pages/_error.tsx

  • _error.tsx
import { NextPageContext } from "next";

function Error({ statusCode }: { statusCode: number }) {
  return (
    <p>
      {statusCode ? `์„œ๋ฒ„์—์„œ ${statusCode}` : "ํด๋ผ์ด์–ธํŠธ์—์„œ"} ์—๋Ÿฌ๊ฐ€
      ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค
    </p>
  );
}

Error.getInitialProps = ({res,err}: NextPageContext) => {
  const statusCode = res.statusCode: err? err.statusCode:"";
  return {statusCode}
}

export default Error;

pages/404.tsx

pages/500.tsx

  • ์„œ๋ฒ„ ์—๋Ÿฌ ํ•ธ๋“ค๋ง
    • error์™€ 500 ์žˆ๋‹ค๋ฉด? 500 ๋จผ์ € ์‹คํ–‰

pages/index.tsx

  • react-pages์—์„œ ์˜๊ฐ์„ ๋ง์•„ ๋งŒ๋“ค์–ด์ง„ ํŽ˜์ด์ง€

| ํŽ˜์ด์ง€ | ๋‚ด์šฉ | ์ฃผ์†Œ | | -------------------------- | -------------------------------------------------------------------------------------------- | ---------------------- | | pages/index.tsx | ์›น ์‚ฌ์ดํŠธ์˜ ๋ฃจํŠธ | / | | pages/hello.tsx | pages ์ƒ๋žต, ํŒŒ์ผ๋ช…์œผ๋กœ ์ฃผ์†Œ ์ ‘๊ทผ | /hello | | pages/hello/world.tsx | ๋””๋ ‰ํ† ๋ฆฌ์˜ ๊นŠ์ด๋งŒํผ ์ฃผ์†Œ ์„ค์ • | /hello/world | | pages/hello/[greeting].tsx | []๋Š”? ์–ด๋–ค ๋ฌธ์ž์—ด๋„ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์Œ (๋‹ค๋งŒ ์ด๋ฏธ ์ •์˜๋œ ์ฃผ์†Œ๊ฐ€ ์žˆ๋‹ค๋ฉด ์ •์˜๋œ ์ฃผ์†Œ๊ฐ€ ์šฐ์„ ) | /hello/1 | | pages/hi/[โ€ฆprops] | [โ€ฆ]๋Š”? ์ „๊ฐœ ์—ฐ์‚ฐ์ž์™€ ๋™์ผ, ๋ชจ๋“  ํ•˜์œ„์˜ ์ฃผ์†Œ (props๋ผ๋Š” ๋ณ€์ˆ˜์˜ ๋ฐฐ์—ด๋กœ ๊ฐ) | /hello/hi/bonjour/good |

// pages/hi/[...props].tsx

export default function HiAll({ props: serverProps }: { props: string[] }) {
  const {
    query: { props },
  } = useRouter();

  useEffect(() => {
    console.log(JSON.stringify(props) === JSON.stringify(serverProps)); // true
  });
  ...
}

export const getServerProps = (context: NextPageContext) =>{
  // ์„œ๋ฒ„์—์„œ ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ
  const {
    query: {props}, // string | string[] | undefined
  } = context
}

server routing๊ณผ client routing์˜ ์ฐจ์ด

  • Nextjs๋Š” ์‚ฌ์ „ ๋žœ๋”๋ง์„ ์ง€์›ํ•œ๋‹ค. = ์ตœ์ดˆ ํŽ˜์ด์ง€ ๋žœ๋”๋ง์„ ์„œ๋ฒ„์—์„œ ์ˆ˜ํ–‰

    • a๋กœ ์ด๋™ํ•˜๋Š” ๊ฒฝ์šฐ: console.log์˜ ๊ฒฝ์šฐ 2๋ฒˆ(์„œ๋ฒ„์—์„œ ๋žœ๋”๋ง/ํด๋ผ์ด์–ธํŠธ hydrate)
    • link๋กœ ์ด๋™ํ•˜๋Š” ๊ฒฝ์šฐ: ํด๋ผ์ด์–ธํŠธ์—์„œ ํ•„์š”ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋งŒ ๋ถˆ๋Ÿฌ์˜จ ๋’ค ๋ผ์šฐํŒ…ํ•˜๋Š” CSR
  • ๋‘ ๊ฐ€์ง€ ์žฅ์ ์„ ์‚ด๋ฆฌ๊ธฐ ์œ„ํ•œ ๋ฐฉ์‹: ์ตœ์ดˆ ํŽ˜์ด์ง€ ๋น ๋ฅด๊ฒŒ ์ œ๊ณต + ์‹ฑ๊ธ€ ํŽ˜์ด์ง€์˜ ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ผ์šฐํŒ…

    • <a> => <Link>
    • window.location.push ๋Œ€์‹  router.push๋ฅผ ์‚ฌ์šฉ

์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋Ÿฐํƒ€์ž„ ์ฒดํฌ

export default function Hello() {
  console.log(typeof window === "undefined" ? "์„œ๋ฒ„" : "ํด๋ผ");
}
  • getServerSideProps๋ฅผ ์ œ๊ฑฐํ•˜๋ฉด?
    • ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋žœ๋”๋ง์ด ํ•„์š” ์—†๋Š”, ๋นŒ๋“œ ์‹œ์ ์— ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋„ ๋˜๋Š” ํŽ˜์ด์ง€๋กœ ๊ฐ„์ฃผ
    • ๋นŒ๋“œ ์‹œ์ ์—์„œ ๋ฏธ๋ฆฌ ํŠธ๋ฆฌ์‰์ดํ‚น
      • ๋ชจ๋“  ์ž‘์—…์ด ์„œ๋ฒ„์—์„œ ์ผ์–ด๋‚˜๋Š” ๊ฒƒ์€ ์•„๋‹˜

pages/api/

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  res.status(200).json({ name: "John Doe" });
}
  • BFF(backend-for-frontend)
  • CORS(Corss-Origin Resource Sharing) ๋ฌธ์ œ๋ฅผ ์šฐํšŒํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ