본문 바로가기
넥스트 제이에스

02.15 next.js의 프리렌더링 공부

by 띠리에이터 2024. 2. 15.
프리렌더링
단순한 의미로는 ~~ 이전에 하는 렌더링 
  • -> 웹페이지 로딩 이전에 하는 렌더링
  • 프리렌더링이 실행되는 시점은?

  • 웹브라우저가 html 코드를 받아오기 전에 렌더링

 

  • 프리렌더링의 장점
    - 초기 로딩이 빨리진다
    -> html이 렌더링된 상태로 제공되기 때문에 

    - 검색엔진 최적화
    -> 비어있는 html이 아니라 렌더링된 html을 미리 받기 때문에 

 

 

  • 프리렌더링의 2가지 방식
    1. 정적 생성
    2. 서버사이드 렌더링

 

1. 정적 생성 
  • 빌드를 하는 시점에 렌더링을 하는 것 (빌드할 때 html을 만드는것)
    - 빌드는 배포하기 전에 소스코드를 실행할 수 있는 형태로 바꿔놓는 것 
  • 소스코드를 빌드하면서 파일로 미리 만들어둠
    -> 웹브라우저로 접속하면 만들어 놓은 걸 그대로 보여줌
    -> 렌더링 된 상태에서 자바스크립트 파일을 로딩 
    -> 리액트 실행 -> 기존에 화면에 렌더링 된 것들이랑 리액트랑 연결
    -> 클라이언트 사이드에서 리액트가 화면 조절
  • 이미 렌더링 된 htrml과 리액트의 데이터를 연결하는 작업을 Hydration이라고 부름
  • build된 next 폴더의 pages -> index.html 파일에서 Format Document를 실행하면 리액트로 작성한 페이지가 html로 렌더링 된다. 
  • 최신 목록을 보여주는 자주 바뀌는 데이터는 정적생성이 적절하지 않다. 

 

  • 정적 생성을 도와주는 함수

    getStaticProps

    - 정적 생성할 때 필요한 데이터를 렌더링 하고 싶을 때, 객체의 props프로퍼티로 넘겨줄 props 객체를 지정하고 페이지 컴포넌트에서 사용할 수 있다.

    - context 파라미터를 사용해서 필요한 params 값이나 쿼리스트링 값을 참조할 수있다. 

    getStaticPath

    - 다이나믹 라우팅을 하는 페이지를 정적 생성을 할 때, 리턴값으로 객체를 리턴하는데 paths라는 배열에서 각 페이지에 해당하는 정보를 넘겨줄 수 있다. 

    - fallback 속성을 사용해 정적 생성되지 않은 페이지를 처리해 줄 것인지 지정할 수 있고 fallback : true로 하면 생성되지 않은 페이지로 접속했을 때 getStaticProps 함수를 실행해 페이지를 만들어서 보여준다. 

    - fallback: true로 지정했으면 {notFound : true} 를 리턴해 데이터를 찾을 수 없을 때 404 페이지로 이동시킬 수 있다 .

 

  • 정적 생성을 하면서 데이터를 가져와서 사용하고 싶을 경우
export const getStaticProps = async () => {
  const res = await axios.get("/products");
  const products = res.data.results;

  return {
    props: { products },
  };
};

export default function Home({ products }) {
  return (
    <>
      <Head>
        <title>DdiShop</title>
      </Head>
      <SearchForm />
      <ProductList className={styles.products} products={products} />
    </>
  );
}

1. getStaticProps 함수를 만들고 리턴값으로  props값을 만듦

2. props는 페이지 컴포넌트에서 가져와서 사용하면 된다. 

 

  • 다이나믹한 페이지를 정적 생성하고 싶을 때 
//다이나믹한 페이지를 정적 생성할 때 어떤 페이지를 생성할 지 정해주는 용도
export const getStaticPaths = async () => {  
  return{
  // params id값으로 각 상품의 id를 넣어준것 , 문자열 형태로 써야함
    paths:[
      {params: {id: "1"}},  
      {params: {id: "2"}},
    ],
   
    fallback: false, 
  }
};

export const getStaticProps = async (context) => {
// 파라미터로 받는 context 객체에서 params 값을 받아올 수 있다.
  const productId = context.params["id"]; //
  const res = await axios.get(`/products/${targetId}`);
  const product = res.data;
  return {
    props: { product },
  };
};

export default function Product({ product }) {
  const [sizeReviews, setSizeReviews] = useState([]);
  const router = useRouter();
  const { id } = router.query;

  async function getSizeReviews(targetId) {
    const res = await axios.get(`/size_reviews/?product_id=${targetId}`);
    const nextSizeReviews = res.data.results ?? [];
    setSizeReviews(nextSizeReviews);
  }

  useEffect(() => {
    if (!id) return;

    getSizeReviews(id);
  }, [id]);
  • 이상한 상품의 id로 들어갔을 때 에러가 나는 경우에는 try, catch문을 사용해서 에러 잡기 

- fallback속성을 사용하면 그때 그때 getStaticProps를 실행해서 미리 정적생성하지 않은 페이지를 보여줄 수 있다. 

-데이터 없이 보여줄 로딩화면구현 -> 리퀘스트를 했을 때 데이터가 없는 경우에는 404 페이지를 보여주도록 설정

//다이나믹한 페이지를 정적 생성할 때 어떤 페이지를 생성할 지 정해주는 용도

export const getStaticPaths = async () => {  
  const res = await axios.get("/products");
  const products = res.data.results;
  const paths = products.map((product) => ({
  //params id값으로 각 상품의 id를 넣어준것 , 문자열 형태로 써야함
    params: { id: String(product.id) },
  }))
  return{
    paths,
    // 없는 경로에 대한 처리 방법을 정해주는 것,false=없는 페이지는 404 에러를 띄움
    // true =정적생성 해놓지 않은 경로로 왔을 때(params: { id: String(product.id) }, 외에) 
	// getStaticProps 를 실행해서 정적 생성을 한다는 의미 
    fallback: true, 
  }
};

export const getStaticProps = async (context) => {
// 파라미터로 받는 context 객체에서 params 값을 받아올 수 있다.
  const productId = context.params["id"]; 
  let product;
  try{
    const res = await axios.get(`/products/${productId}`);
    product = res.data;
  } catch{
    return { // 에러가 발생하면 404 에러를 띄움
      notFound: true,
    };
  }
  return {
    props: { product },
  };
};

// 페이지 컴포넌트는 내려준 props를 기준으로 렌더링함
export default function Product({ product }) {
  const [sizeReviews, setSizeReviews] = useState([]);
  const router = useRouter();
  const { id } = router.query;

  async function getSizeReviews(targetId) {
    const res = await axios.get(`/size_reviews/?product_id=${targetId}`);
    const nextSizeReviews = res.data.results ?? [];
    setSizeReviews(nextSizeReviews);
  }

  useEffect(() => {
    if (!id) return;

    getSizeReviews(id);
  }, [id]);

  if (!product) return(
    <div>상품 정보를 불러오는 중입니다...
    </div>
  );

 

2. 서버사이드 렌더링
  • 렌더링 된 html을 보여주는데 정적 생성이랑 다른 점은
    - 웹브라우저가 리퀘스트를 보낼 때마다 서버가 매번 렌더링해서 보내주는 것 
  • 서버사이드 렌더링도 정적 생성이랑 비슷함
export const getServerSideProps = async (context) => {
  // context 객체를 파라미터로 받아서
  const q = context.query["q"];
  // 쿼리스트링을 가져옴
  const res = await axios.get(`/products/?q=${q}`);
  // 해당 쿼리스트링을 가진 상품을 가져옴
  const products = res.data.results ?? [];
  // 가져온 상품을 변수에 담음
  return {
    props: {
      products,
      q,
    },
  };
};

export default function Search({ q, products }) {
  return (
    <div>
      <Head>
        <title>{q} 검색 결과</title>
      </Head>
      <SearchForm initialValue={q} />
      <h2 className={styles.title}>
        <span className={styles.keyword}>{q}</span> 검색 결과
      </h2>
      <ProductList className={styles.productList} products={products} />
    </div>
  );

getServerSideProps 함수를 사용, 

  • 들어오는 리퀘스트에 따라서 다르게 프리렌더링 하거나
  • 자주 바뀌는 데이터를 프리렌더링 하고 싶을 때 사용 
  • getStaticProps 와 getServerSideProps 는 같이 사용하면 안된다. 

'넥스트 제이에스' 카테고리의 다른 글

mongoDB였던것  (0) 2024.02.26
next.js공부중  (0) 2024.02.14