[Next] Rendering, Fetching전략

Zero·2023년 10월 18일
0

[Next]

목록 보기
1/7
post-thumbnail

다양한 렌더링

렌더링 전략이란 웹 페이지 또는 웹 애플리케이션을 웹 브라우저에 제공하는 방법을 의미합니다. 리액트의 경우 CSR, PHP의 경우 SSR을 지원을 하고있습니다. 하지만 Next의 경우 다양한 렌더링 전략을 제공합니다.

1. 클라이언트 사이드 렌더링(CSR)

웹 페이지 방문 -> 해당 사이트의 html 코드와 js 파일을 전부 받아옵니다 -> 받아온 html 파일에 js파일과 css파일로 마크업을 진행하여줍니다.

표준 리액트 앱은 서버에서 자바스크립트 번들을 클라이언트로 전송한 다음 렌더링을 시작합니다. create-react-app(CRA)를 사용해봤다면 화면이 텅텅 비어있는 것을 본 적이 있을 것입니다. 서버가 웹 애플리케이션이 필요로하는 스크립트와 스타일만 포함된 기본 HTML 마크업만 전송하기 때문입니다.

CSR의 동작과정은 다음과 같습니다.

  1. 배포된 URL로 접근하면 서버로부터 해당 url로 배포된 html 마크업을 받아 화면에 렌더링을 시작합니다.

  2. CRA가 빌드 과정 동안 주입한 script, link 태그의 자바스크립트 번들과 css 파일을 다운로드합니다.

  3. 해당 브라우저가 이를 통해 전체 애플리케이션을 렌더링합니다.
    CSR의 동작과정

CSR의 사용할 때의 이점은 다음과 같습니다.

  • 쉬운 페이지 전환

    • 클라이언트에서의 내비게이션은 브라우저 화면을 새로 고칠 필요 없이 다른 페이지로의 이동을 가능하게 만듭니다.
  • 지연된 로딩과 성능

    • CSR을 사용하면 웹 앱에서는 최소로 필요한 html 마크업만 렌더링을 합니다. 사용자가 버튼을 클릭하면 보이는 모달의 경우 동적으로 생성되기 때문에 실제로는 존재하지 않습니다.
  • 서버 부하 감소

    • 렌더링 과정이 서버가 아닌 브라우저에서 일어나기 때문에 서버가 할 일이라고는 간단한 html 파일을 전송하는 정도입니다.
  • 자연 스러운럽게 느껴지는 웹 애플리케이션

    • 전체 자바스크립트 번들을 다운로드하여 웹 애플리케이션이 렌더링할 모든 페이지가 이미 브라우저에 다운로드가 되어있습니다. 다른 페이지로 이동하면 서버에서 해당 페이지에 해당하는 새로운 콘텐츠를 다운로드하지 않고 그냥 페이지의 콘텐츠를 새로운 것으로 바꿉니다.

이러한 장점들은 단점이 될 수도 있습니다. 간단한 html 파일만을 보내기 때문에 네트워크 속도가 느린 환경에서는 페이지를 구성하는 scriptcss 파일을 받는데에 오랜 시간이 소요도리 수 있습니다. 이러한 경우 오랫동안 빈페이지를 바라보고 있어야 합니다.


2. 서버 사이드 렌더링(SSR)

서버 사이드 렌더링은 PHP, 파이썬과 같이 html페이지를 웹 브라우저로 전송하기 전에 서버에서 전부 렌더링하는 방법으로 렌더링하여 도착하고 모든 자바스크립트 코드가 적재되면 동적으로 페이지 내용을 렌더링합니다.

Next.js에서도 마찬가지로 각 요청에 따라 서버에서 html 페이지를 동적으로 렌더링하여 웹 브라우저로 전송할 수 있습니다. 또한 서버에서 렌더링한 페이지에 스크립트 코드를 집어넣어서 나중에 웹 페이지로 동적으로 처리할 수도 있는데 이를 hydration 이라고 합니다.

SSR의 동작과정은 다음과 같습니다

웹 페이지 방문 -> 프론트 엔드 서버 (HTML 파일 요청) -> 백엔드 서버(렌더링 준비가 끝난 HTML 반환) -> 브라우저(받아온 HTML에 JS를 입혀 동적인 웹 페이지로 만들어줍니다.)

  1. 배포된 URL로 접근하면 서버로부터 해당 url로 배포된 htmlscript파일을 받아 화면에 렌더링을 시작합니다.

  2. 받아온 html 페이지에 모든 script코드가 적재가 된다면 해당 DOM 위에 각 스크립트 코드를 하이드레이션 합니다.

  3. 해당 브라우저가 이를 통해 전체 애플리케이션을 렌더링합니다.
    SSR의 동작과정

위같은 이유때문에 페이지를 새로 고침하지 않고도 아무 문제 없이 사용자와 웹 페이지를 하이드레이션합니다. 그래서 페이지를 새로 고치지 않고도 아무 문제없이 상호작용할 수 있습니다.

리액트 하이드레이션의 관한 내용은 다음 사이트를 통해서 확인할 수 있습니다.

리액트 하이드레이션 덕분에 웹 앱은 싱글 페이지 애플리케이션(SPA)처럼 작동할 수 있습니다. 클라이언트 사이드 렌더링(CSR)서버 사이드 렌더링(SSR)의 장점을 모두 가지는 것입니다.

SSR을 사용할 때의 이점은 다음과 같습니다.

  • 보안성

    • 페이지를 서버에서 렌더링을 한다는 것은 쿠키 관리, 주요 API, 데이터 검증 등과 같은 작업을 서버에서 처리한다는 뜻이며, 중요한 데이터를 클라이언트에 노출할 필요가 없기 때문에 더 안전합니다.
  • 호환성

    • 클라이언트 환경이 자바스크립트를 사용하지 못하거나 오래된 브라우저를 사용하더라도 웹 페이지를 제공할 수 있습니다.
  • 검색엔진 최적화

    • JS를 이용한 렌더링이 아니므로 SEO(검색 엔진 최적화)가 가능합니다.

사용방법

Next 13 이전

// getServerSideProps는 매 요청 시 호출이 됩니다.
export async function getServerSideProps(){ 
  
  // 외부 API로부터 데이터를 가져옵니다.
  
	const userRequest = await fetch('https://topdragon.co.kr/api/user/info');
  	const userData = await userRequest.json();
  
  // 가져온 데이터를 props로 전달합니다.
  
  	return {
    	props: {
        	user: userData,
        }
    }
}

// 렌더링이 되는 페이지
function IndexPage(props) {
  
  	// props로 받아와서 사용을 할 수 있습니다.
  
	return <div>Welcome, {props.user.name}</div>
} 
Next 13 이후

// 매번 요청시마다 다시 요청을 합니다.

fetch(URL, { cache: 'no-store' });

export default funciton Home(){
  const userReq = fetch('https://topdragon.co.kr/api/user/info', { cache: 'no-store' })
  const user = userReq.json();
  
  return <div>Welcome, {user.name}</div>
}

3. 정적 사이트 생성 (SSG)

정적 사이트 생성(SSG)란 일부 또는 전체 페이지를 빌드 시점에 미리 렌더링 하는 것을 의미합니다. 웹 애플리케이션을 빌드할 때 내용이 거의 변하지 않는 경우 정적 페이지 형태로 제공하는 것이 좋습니다. Next.js는 이런 페이지를 빌드 과정에서 정적 페이지로 미리 렌더링해서 html 마크업 형태로 제공합니다. SSR과 비슷합니다. 또한 리액트 하이드레이션 덕분에 정적페이지에서도 여전히 사용자와 웹 페이지 간의 상호 작용이 가능합니다.

SSG를 사용할 때의 이점은 다음과 같습니다.

  • 쉬운 확장

    • 정적 페이지는 단순한 html 파일임로 CDN을 통해 파일을 제공하거나 캐시에 저장하기 쉽습니다. 정적 페이지의 경우 별도의 연산 없이 정적 자원의 형태로 제공되기 때문에 서버에 부하를 거의 주지 않습니다.
  • 성능 최적화

    • 빌드 시점에 html을 렌더링하기 때문에 페이지를 요청해도 클라이언트나 서버가 처리할 필요가 없습니다. 서버가 쪽에 요구하는 데이터라고는 정적 html을 마크업 내에 미리 렌더링한 내용 정도만 받아오면 됩니다. 따라서 각 요청별로 발생할 수 있는 지연시간을 최소화 할 수 있습니다.
  • 안전한 API 요청

    • 필요한 모든 정보가 빌드 시점에 미리 페이지로 렌더링이 되어있기 때문에 페이지 렌더링을 위해 민감하고 중요한 데이터를 클라이언트에 보낼 필요가 없습니다.

사용방법

Next 13 이전
export async function getStaticProps(){
	const userRequest = await fetch('https://topdragon.co.kr/api/user/info');
  	const userData = await userRequest.json();
  
  	const productReq = await fetch('https://topdragon.co.kr/api/product/list');
  	const productData = await productReq.json();
  
	return {
    	props : {
        	user: userData,
          	product : productData,
        },
    }; 
}

function IndexPage(props) {
	return (
    	<div>
      		<Paradise
      			user={props.user}
				product={props.product}
      		/>
      	</div>
    )
}

export default IndexPage;
Next 13

function IndexPage(props) {
  	const userRequest = await fetch('https://topdragon.co.kr/api/user/info', { cache: 'force-cache' });
    const productReq = await fetch('https://topdragon.co.kr/api/user/info', { cache: 'force-cache' });
  	
  	const userData = await userRequest.json();
  	const productData = await productReq.json();
  
	return (
    	<div>
      		<Paradise
      			user={userData}
				product={productData}
      		/>
      	</div>
    )
}

SSG를 사용할 때 일어날 수 있는 문제점은 다음과 같습니다.

웹 페이지를 만들어 배포를 하고나면 다음 배포 전까지는 내용이 변하지 않는다는 것입니다.

Next.js는 이문제를 해결하기 위해서 ISR과 같은 해결책을 냈습니다.

4. 증분 정적 재생성 (ISR)

ISR을 사용하면 Next.js가 어느 정도의 주기로 정적 페이지를 다시 렌더링하고 해당 내용을 업데이트할지 정할 수 있습니다.

사용방법

Next 13 이전
export async function getStaticProps(){
	const userRequest = await fetch('https://topdragon.co.kr/api/user/info');
  	const userData = await userRequest.json();
  
  	const productReq = await fetch('https://topdragon.co.kr/api/product/list');
  	const productData = await productReq.json();
  
	return {
    	props : {
        	user: userData,
          	product : productData,
        },
       revalidate: 600 // 시간을 초 단위로 나타낸 값 (10분)
    }; 
}

function IndexPage(props) {
	return (
    	<div>
      		<Paradise
      			user={props.user}
				product={props.product}
      		/>
      	</div>
    )
}

export default IndexPage;
Next 13 이후

function IndexPage(props) {
  	const userRequest = await fetch('https://topdragon.co.kr/api/user/info', { next: { revalidate: 10 } });
    const productReq = await fetch('https://topdragon.co.kr/api/user/info', { next: { revalidate: 10 } });
  	
  	const userData = await userRequest.json();
  	const productData = await productReq.json();
  
	return (
    	<div>
      		<Paradise
      			user={userData}
				product={productData}
      		/>
      	</div>
    )
}
profile
개발자처럼 생각하기

0개의 댓글