[ํ”„๋กœ์ ํŠธ] Next.js_๐Ÿซ  4

ํ•จ๋ฏผํ˜ยท2023๋…„ 11์›” 30์ผ
0

ํ”„๋กœ์ ํŠธ

๋ชฉ๋ก ๋ณด๊ธฐ
11/18

๋“ค์–ด๊ฐ€๊ธฐ ์ „์—...

์ง€๊ธˆ๊นŒ์ง€ ์ƒ๊ฒผ๋˜ ์˜๋ฌธ๋“ค์„ ์ •๋ฆฌํ•ด๋ณด์ž

Q1. SSR์€ ๋นŒ๋“œ์‹œ์ ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค ๊ฐ€์ ธ์˜ค๋Š”๊ฒŒ ์•„๋‹Œ๋ฐ ์–ด๋–ป๊ฒŒ SEO ์ธก๋ฉด์— ์œ ๋ฆฌํ•œ ๊ฑธ๊นŒ?

SSR(์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง)์€ ๊ฐ ์š”์ฒญ๋งˆ๋‹ค ์„œ๋ฒ„ ์ธก์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•จ. ๋”ฐ๋ผ์„œ SSR์€ ๋นŒ๋“œ ์‹œ์ ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜ค์ง€ ์•Š์Œ.
SSR์€ ์ดˆ๊ธฐ ๋กœ๋”ฉ ์‹œ์— ์™„์ „ํ•œ HTML ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณต

Q2. CSR์„ ํ•ด๋„ ๊ฒฐ๊ตญ api๋ฅผ ์š”์ฒญํ•˜๋Š”๊ฑด ์„œ๋ฒ„์— ์š”์ฒญํ•˜๋Š”๊ฑฐ ์•„๋‹Œ๊ฐ€? ์ด๊ฒŒ SSR๊ณผ ์ •ํ™•ํžˆ ๋ญ๊ฐ€ ๋‹ค๋ฅธ๊ฑฐ์ง€? SSR๋„ ์„œ๋ฒ„์— ์š”์ฒญ์„ํ•˜๊ณ  CSR๋„ ์„œ๋ฒ„์— ์š”์ฒญํ•˜์ž–์•„

์ดˆ๊ธฐ ๋กœ๋”ฉ ์‹œ์ ์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์œ„์น˜๊ฐ€ ์„œ๋ฒ„์ธ์ง€ ํด๋ผ์ด์–ธํŠธ์ธ์ง€๊ฐ€ ๋‘ ๋ฐฉ์‹์˜ ์ฃผ์š”ํ•œ ์ฐจ์ด์ 
CSR์˜ ๊ฒฝ์šฐ, ์ดˆ๊ธฐ์—๋Š” ๋นˆ ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋˜๊ณ , ์ดํ›„ JavaScript๊ฐ€ ์‹คํ–‰๋˜๋ฉด์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ€์ ธ์™€์ง€๊ณ  ํŽ˜์ด์ง€๊ฐ€ ์—…๋ฐ์ดํŠธ๋จ.
๋ฐ˜๋ฉด์— SSR์˜ ๊ฒฝ์šฐ, ์„œ๋ฒ„๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๋ฉด์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์™€์„œ ์™„์ „ํ•œ ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณตํ•จ.

CSR:
์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€์— ์ ‘์†
ํŽ˜์ด์ง€๋Š” ์ดˆ๊ธฐ์— ๋นˆ ์ƒํƒœ๋กœ ๋กœ๋“œ
ํด๋ผ์ด์–ธํŠธ ์ธก JavaScript๋Š” API๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ด
๋ฐ์ดํ„ฐ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ถˆ๋Ÿฌ์™€์ง€๋ฉด, ํŽ˜์ด์ง€๋Š” ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ Œ๋”๋ง

SSR:
์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€์— ์ ‘์†
์„œ๋ฒ„๋Š” ์ดˆ๊ธฐ ์š”์ฒญ์— ๋Œ€ํ•ด ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๋ฉด์„œ API๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜ด
์„œ๋ฒ„๋Š” ์™„์ „ํ•œ ํ˜•ํƒœ์˜ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณต, ํŽ˜์ด์ง€์—๋Š” ๋ฏธ๋ฆฌ ๋ถˆ๋Ÿฌ์˜จ ๋ฐ์ดํ„ฐ๊ฐ€ ํฌํ•จ๋˜์–ด์žˆ์Œ.

Q3. SSG,SSR,CSR ๊ฐ๊ฐ API๋ฅผ ๋ถ€๋ฅด๋Š” ์‹œ์ ์ด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

SSG->SSR->CSR
SSG์€ ๋นŒ๋“œ ์‹œ์ ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋ฏ€๋กœ, ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€์— ์ ‘์†ํ–ˆ์„ ๋•Œ ๊ฐ€์žฅ ๋น ๋ฅด๊ฒŒ ๋ Œ๋”๋ง๋จ.
SSR์€ ๊ฐ ์š”์ฒญ๋งˆ๋‹ค ์„œ๋ฒ„ ์ธก์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋ฏ€๋กœ, SSG๋ณด๋‹ค๋Š” ๋А๋ฆด ์ˆ˜ ์žˆ์ง€๋งŒ, CSR๋ณด๋‹ค๋Š” ๋น ๋ฅด๊ฒŒ ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณตํ•จ.
CSR์€ ์ดˆ๊ธฐ์—๋Š” ๋นˆ ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋˜๊ณ , ์ดํ›„์— ํด๋ผ์ด์–ธํŠธ ์ธก JavaScript๊ฐ€ ์‹คํ–‰๋˜๋ฉด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ด.

โœ… SSR ์ง์ ‘์‚ฌ์šฉํ•ด๋ณด๊ธฐ

SHOPํ™”๋ฉด ์นดํ…Œ๊ณ ๋ฆฌ ๋ฐ์ดํ„ฐ, ์ œํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ๋•Œ SSR,SSG ์ค‘ ์„ ํƒ์„ ํ•ด์•ผํ•จ.

๊ด€๋ฆฌ์ž๊ฐ€๊ฐ€ ์ œํ’ˆ ๋ฐ์ดํ„ฐ ํ•˜๋‚˜๋ฅผ ์ถ”๊ฐ€ํ–ˆ์„ ๊ฒฝ์šฐ, ์‚ฌ์šฉ์ž๊ฐ€ ๋‚ด๊ฐ€ ์ถ”๊ฐ€ํ•œ ๊ทธ ์ œํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์œผ๋ ค๋ฉด....

  • SSG๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ
    getStaticProps์—์„œ revalidate ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ•จ. revalidate์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด, ์ •์  ์ƒ์„ฑ๋œ ํŽ˜์ด์ง€๋Š” ๋นŒ๋“œ๋œ ์ดํ›„์—๋งŒ ์—…๋ฐ์ดํŠธ๋˜๋ฉฐ, ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜์˜ํ•˜๋ ค๋ฉด ๋ช…์‹œ์ ์œผ๋กœ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋นŒ๋“œ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•ด์•ผํ•จ.
    revalidate์˜ ๊ฒฝ์šฐ ํŽ˜์ด์ง€ ๋‚ด์šฉ์ด ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ๋งŒ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ํŽ˜์ด์ง€๋ฅผ ๊ฐฑ์‹ ํ•จ. ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด ์ด์ „์— ์ƒ์„ฑ๋œ ์ •์  ํŽ˜์ด์ง€๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•จ.

  • SSR์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ
    ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญ ์‹œ์— ๋™์ ์œผ๋กœ ๊ฐ€์ ธ์™€์„œ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์Œ.
    ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ ์‹œ์— ๋นŒ๋“œ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•  ํ•„์š”๊ฐ€ ์—†์Œ.

SSR ๊ตฌํ˜„ ์˜ˆ์‹œ

export async function getServerSideProps() {
  const queryClient = new QueryClient();

  const productQuery = await queryClient.prefetchQuery(
    [QUERYKEYS.LOAD_PRODUCT],
    loadMarketProduct,
  );

  const categoryQuery = queryClient.prefetchQuery(
    [QUERYKEYS.ADMIN_GET_CATEGORY],
    adminGetCategory,
  );

  await Promise.all([productQuery, categoryQuery]);

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  };
}
  const queryClient = useQueryClient();

  const productData = queryClient.getQueryData([QUERYKEYS.LOAD_PRODUCT]) as {
    data: {
      content: Array<any>;
    };
  };

  const categoryData = queryClient.getQueryData([
    QUERYKEYS.ADMIN_GET_CATEGORY,
  ]) as { data: Array<any> };

getServerSideProps ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„ ์ธก์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌ
ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ๋Š” useQueryClient ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ผํ•œ ์ฟผ๋ฆฌ ํด๋ผ์ด์–ธํŠธ์— ์ ‘๊ทผํ•˜๊ณ , ์ด์ „์— ๋ถˆ๋Ÿฌ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ด

์ด ๊ธ€์„ ์ž‘์„ฑํ• ๋•Œ๊นŒ์ง€๋งŒ ํ•ด๋„ SSR๋กœ ๊ตฌํ˜„ํ•˜๋ ค๊ณ  ํ–ˆ์ง€๋งŒ, SSG๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •

์ด์œ  : ๊ด€๋ฆฌ์ž๋Š” ์ƒˆ๋กœ์šด ์ œํ’ˆ ๋ฐ์ดํ„ฐ๋Š” ์ผ์ฃผ์ผ์— ํ•œ๋ฒˆ ์—…๋ฐ์ดํŠธํ•˜๊ณ , ์นดํ…Œ๊ณ ๋ฆฌ ๋ฐ์ดํ„ฐ์˜ ๊ฒฝ์šฐ๋Š” ๊ฑฐ์˜ ์ž˜ ๋ณ€ํ•˜์ง€ ์•Š์Œ. ์ด๋Ÿด ๊ฒฝ์šฐ SSG๋ฅผ ํ•˜๋Š”๊ฒŒ ํšจ์œจ์ ์ž„.

SSG ๊ตฌํ˜„

export async function getStaticProps() {
  const queryClient = new QueryClient();

  // Prefetch queries
  await queryClient.prefetchQuery([QUERYKEYS.LOAD_PRODUCT], loadMarketProduct);
  await queryClient.prefetchQuery(
    [QUERYKEYS.ADMIN_GET_CATEGORY],
    adminGetCategory,
  );

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
    revalidate: 10,
  };
}

์•„๋ž˜๋Š” SSR๊ณผ ๋™์ผ

๋!...

๐Ÿซ 

profile
Born to be FE developer ๐Ÿง‘๐Ÿปโ€๐Ÿ’ป

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