๐Ÿ’ป TIL 23.03.10

๊น€์˜์šฐ(Yeongwoo Kim)ยท2023๋…„ 3์›” 11์ผ
0
post-thumbnail

๐Ÿซ  ์—…๋กœ๋“œ๊ฐ€ ๋Š๋ ธ๋˜ ์ด์œ ...

  1. ๊ธฐ์กด ClubStudy ํŽ˜์ด์ง€๋Š” ํ•˜๋“œ์ฝ”๋”ฉ์œผ๋กœ ์ž‘์„ฑ๋˜์–ด์žˆ์—ˆ๋‹ค..(์ž‘์—… ์ดˆ๋ฐ˜ ๋‚˜์˜ ์‹ค๋ ฅ ๋ฏธ์ˆ™๊ณผ ๊ธฐํ•œ์ด ์งง์•˜์–ด์„œ)
  2. ๊ทธ๋ž˜์„œ ํ•ด๋‹น๋ถ€๋ถ„์„ API๋ฅผ ๋ฐ›์•„์™€์„œ ์ ์šฉํ•˜๋ คํ•˜๋‹ค ๋ณด๋‹ˆ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜๊ฐ€ ์žˆ์—ˆ๋‹ค.
  3. ํ•˜์ง€๋งŒ ์˜ค๋ฅ˜๊ฐ€ ํ•˜๋‚˜๋ฅผ ํ•ด๊ฒฐํ•˜๋‹ˆ ๋‹ค๋ฅธ ์˜ค๋ฅ˜๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ–ˆ๊ณ , ์ฒœ์ฒœํžˆ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋Œ์•„๊ฐ€๋ณด์ž ๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.
  4. ํ•œ๋ถ€๋ถ„๋‹น ํ•˜๋‚˜์”ฉ ์—…๋กœ๋“œ๋ฅผ ํ–ˆ์–ด์•ผํ–ˆ๋Š”๋ฐ...๋‚˜๋ฅผ ๊ณผ์‹ ํ•ด์„œ ํ•˜๋ฃจ๋งŒ์— ๋‹ค ํ•ด๊ฒฐํ•  ์ค„ ์•Œ์•˜๋‹ค..
  5. ์ด์ œ ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๊ณ , ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ–ˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž.

โœ… ๋ฌธ์ œ

1. CSR vs SSG vs SSR

  • CSR์€ JSํŒŒ์ผ์„ ์ „๋ถ€ ๋กœ๋“œํ•ด์•ผ, ํŽ˜์ด์ง€ ์ •๋ณด๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ SEO์— ์ทจ์•ฝํ•˜๋‹ค. ํ•˜์ง€๋งŒ ํ•ด๋‹น ์›น์‚ฌ์ดํŠธ๋Š” ๋งˆ์ผ€ํŒ…์„ ์œ„ํ•ด SEO๊ฐ€ ํ•„์š”ํ•œ ์ƒํ™ฉ์ด๊ธฐ ๋•Œ๋ฌธ์— CSR์€ ์ œ์™ธํ–ˆ๋‹ค.
  • SSG์™€ SSR ์ค‘์— ์„ ํƒ์„ ํ•ด์•ผํ–ˆ๋‹ค. SSR์˜ ์žฅ์ ์œผ๋กœ๋Š” ๋” ๋งŽ์€ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€ ์‘๋‹ต์„ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ ํŽ˜์ด์ง€ ํŠน์„ฑ์ƒ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ”๋€Œ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋นˆ๋ฒˆํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์†๋„๊ฐ€ ๋” ๋น ๋ฅธ SSG๋ฅผ ์„ ํƒํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

2. API์—ฐ๋™

  • Next JS์—์„œ SSG ๋ฐฉ์‹์œผ๋กœ API ์—ฐ๋™ํ•˜๋Š” ๋ฐฉ๋ฒ•์—๋Š” getStaticProps๊ฐ€ ์žˆ๋‹ค.
export const getStaticProps: GetStaticProps = async (context) => {
  const res = await fetch('https://.../posts')
  const posts = await res.json()
  
  // ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด notFound๋ฅผ ๋ณด๋‚ธ๋‹ค 
  if (!data) {
    return {
      notFound: true,
    }
  }

  return {
    props: {
      posts,
    },
  }
}
  • ๋ฉ”์ธํŽ˜์ด์ง€์—์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์ง€๋งŒ, detail_study์—์„œ ํ•ด๋‹น ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

๐Ÿ” ์›์ธ ํŒŒ์•…

1. detail_study๋Š” ์–ด๋–ป๊ฒŒ ์ด๋ค„์ ธ์žˆ๋‚˜.

  • ๋ฉ”์ธํŽ˜์ด์ง€์—์„œ ์Šคํ„ฐ๋”” ์นด๋“œ๋ฅผ ๋ˆ„๋ฅด๋ฉด ํ•ด๋‹น ์Šคํ„ฐ๋””์˜ ์ƒ์„ธํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ฒŒ ํ•ด์•ผํ–ˆ๋‹ค. ์ด๋•Œ ์ƒ๊ฐํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ๋‘๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.
    1. router.query๋ฅผ ์ด์šฉํ•˜์—ฌ ์Šคํ„ฐ๋”” ์นด๋“œ๋ฅผ ํด๋ฆญํ–ˆ์„ ๋•Œ, ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๋ฉด์„œ studyId๋ฅผ ํ•จ๊ป˜ ๋ณด๋‚ด์„œ API์— studyId๋ฅผ ๋ณด๋‚ด ํ•ด๋‹น ์Šคํ„ฐ๋”” ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๋ฐฉ๋ฒ•
    2. Next JS์˜ dynamic routing์„ ์ด์šฉํ•ด์„œ ๋™์ ์œผ๋กœ studyId์— ๋”ฐ๋ผ ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๋„๋ก (ex : studyId๊ฐ€ 1์ผ ๊ฒฝ์šฐ clubstudy.net/detail_study/1) ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.
  • ํ•ด๋‹น ๋ณด๊ธฐ๋“ค ์ค‘ ํ•œ๋ฒˆ ๊ตฌ์„ฑ์„ ํ•˜๋ฉด ๊ด€๋ฆฌ์ž์˜ ๊ฐœ์ž…์ด ์—†๋Š” 2๋ฒˆ์„ ํƒํ•ด์„œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.
<StudyCardBox
	onClick={() => {
    	const path = `/detail_study/${Props.id}`;
    	router.push({
    		pathname: path,
    	});
    }}
	maxWidth="xs"
>

2. getStaticPaths๋ž€?

  • If a page has dynamic routes and uses getStaticProps it needs to define a list of paths that have to be rendered to HTML at build time.
    ๊ณต์‹๋ฌธ์„œ
  • ์ฆ‰, ๋™์ ๋ผ์šฐํŒ… + getStaticProps๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ getStaticPaths๋กœ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•ด๋†”์•ผ ํ•œ๋‹ค.
  • prerenderingํ•˜๋Š” ๊ณผ์ •์—์„œ ๊ฒฝ๋กœ๊ฐ€ ์™ธ๋ถ€์— ์˜์กดํ•˜๊ฒŒ ๋์„๋•Œ, getStaticProps๋งŒ์œผ๋กœ๋Š” ํ•  ์ˆ˜ ๊ฐ€ ์—†๋‹ค. ์™œ๋ƒํ•˜๋ฉด /detail_study/${Props.id}์—์„œ id์— ์–ด๋–ค ๊ฐ’์ด ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๊ณ , ์ง€๊ธˆ ์•Œ๊ณ  ์žˆ๋”๋ผ๋„ ์ถ”๊ฐ€๋˜๋ฉด ๋‹ฌ๋ผ์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
  • getStaticPaths๋Š” ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋นŒ๋“œ์‹œ์— ํ˜ธ์ถœ๋˜๋ฉฐ id์—๋Š” ์–ด๋–ค ๊ฐ’๋“ค์ด ์žˆ๋Š”์ง€ ๋ฏธ๋ฆฌ ํŒŒ์•…ํ•ด์„œ getStaticProps์— ์•Œ๋ ค์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

์‹œ๋„

export const getStaticPaths: GetStaticPaths = async () => {
  // posts๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•ด fetch
  const res = await fetch(`https://api-/`);
  const posts = await res.json();
  // pre-renderํ•  Path๋ฅผ ์–ป์Œ (posts๋ฅผ ํ†ตํ•ด์„œ)
  const paths = posts.map((study: StudyInfoType) => ({
    params: { post: study.studyId.toString() },
  }));
  return { paths, fallback: false };
};

// ๋นŒ๋“œ๋  ๋•Œ ์‹คํ–‰
export const getStaticProps: GetStaticProps = async (context) => {
  // params๋Š” post `id`๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค
  const { id } = context.params as IParams;
  const res = await axios.get(
    `http://api-/{id}`,
  );
  const data = res.data;
  // ํ•ด๋‹น ํŽ˜์ด์ง€์— props๋กœ ๋ณด๋ƒ„
  return { props: { study: data } };
};

  • ํ•˜์ง€๋งŒ ํ•ด๋‹น ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค. ์ง„์งœ ๋งŽ์ด ์ฐพ์•„๋ณด๊ณ  ๋“œ๋””์–ด ํ•ด๊ฒฐ๋ฒ•์„ ์ฐพ์€์ค„ ์•Œ๊ณ  ๊ธฐ๋ปค์—ˆ๋Š”๋ฐ ๋‹ค๋ฅธ ์˜ค๋ฅ˜๊ฐ€ ๋œฌ๋‹ค.
  • ๊ทธ๋ ‡๋‹ค๋Š” ๊ฒƒ์€ Path๋ฅผ ํ†ตํ•ด ๊ฐ€์ ธ์™”๋‹ค๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ parameter์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒƒ ๊ฐ™์•„ ๋‹ค์‹œ ํ™•์ธ์„ํ–ˆ๋‹ค.
  • ์ •๋ง ๊ฐ„๋‹จํ•œ ๋ฌธ์ œ๋กœ path์—์„œ ๋ณด๋‚ด๋Š” params์—๋Š” post๊ฐ€ ์•„๋‹Œ StaticProps์˜ ๊ฒƒ ๊ณผ ๊ฐ™๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ–ˆ๋‹ค.

ํ•ด๊ฒฐ

export const getStaticPaths: GetStaticPaths = async () => {
  // posts๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•ด fetch
  const res = await fetch(`https://api-/`);
  const posts = await res.json();
  // pre-renderํ•  Path๋ฅผ ์–ป์Œ (posts๋ฅผ ํ†ตํ•ด์„œ)
  const paths = posts.map((study: StudyInfoType) => ({
    params: { id: study.studyId.toString() },
  }));
  return { paths, fallback: false };
};

๋Š๋‚€์ 

  1. ํŽ˜์ด์ง€ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐฉ์‹๋ถ€ํ„ฐ API ์—ฐ๋™, Dynamic Routing, StaticPaths, StaticProps๊นŒ์ง€ ํ•œ๋ฒˆ์— ์ •๋ง ๋งŽ์€ ๊ณต๋ถ€๋ฅผ ํ•œ ๊ฒƒ ๊ฐ™์•˜๋‹ค.
  2. ์ฒ˜์Œ์œผ๋กœ ํ•˜๋Š” ๊ฒƒ๋“ค์ด ๋งŽ์•„์„œ ๊ฐœ๋ฐœ ์„ค๊ณ„๋ถ€ํ„ฐ ํ•˜์ง€ ์•Š๊ณ , ๋งจ๋ฐ”๋‹ฅ์— ํ—ค๋”ฉ์œผ๋กœ ์‹œ์ž‘ํ•˜๋‹ค๋ณด๋‹ˆ ๋ง‰ํžˆ๋Š” ๋ถ€๋ถ„์ด ๋งŽ์•˜๋‹ค. ํ•˜์ง€๋งŒ ์ด๋ฒˆ ๊ฒฝํ—˜์„ ํ†ตํ•ด์„œ ์–ด๋–ป๊ฒŒ ์„ค๊ณ„๋ฅผ ํ• ์ง€ ์•Œ๊ฒŒ ๋˜์—ˆ๊ณ , ๊ณต๋ถ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋งŽ์€ ๋„์›€์ด ๋œ ๊ฒƒ ๊ฐ™์•˜๋‹ค.
  3. ์ฐจ๊ทผ์ฐจ๊ทผ ํ•˜๋‚˜์”ฉ ํ’€์–ด๋‚˜๊ฐ€๋Š” ๊ณผ์ •์ด ์•„์ง๊นŒ์ง€ ๋‚˜๋Š” ๋„ˆ๋ฌด ์žฌ๋ฐŒ๋‹ค. ์•ž์œผ๋กœ๋„ ์žฌ๋ฐŒ๊ธธ ๋ฐ”๋ผ๋ฉฐ ์˜ค๋Š˜ ๊ธฐ๋ก ๋!

๐Ÿ“„ ์ฐธ์กฐ

https://mui.com
https://agilejung.tistory.com/entry/MUI%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95
https://ajdkfl6445.gitbook.io/study/web/csr-vs-ssr-vs-ssg
https://han-py.tistory.com/489
https://velog.io/@devstone/Next.js-100-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0-feat.-initialProps-webpack-storybook#-getstaticpaths-static-generation

profile
์ฐจ๊ทผ์ฐจ๊ทผ ์„ฑ์žฅํ•˜๋Š” ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค

0๊ฐœ์˜ ๋Œ“๊ธ€