첫번째. Nextjs의 SSR

유원근·2022년 12월 26일
10
post-thumbnail

문제의 과정들을 살펴보기에 앞서 이 시리즈를 이해하기 위한 과정 하나를 지나가 보겠습니다.

SSR (Server-Side-Rendering)

사실 이제는 SSR에 대해 설명하는 것은 너무 많은 정보들이 있기 때문에 의미가 많이 없을것 같습니다😅.

아래 글과 같이 100번은 넘게 저의 검색엔진에 노출된 SSR에 대해 잘 정리해주신 네이버 D2의 글과 다른 위대한 자료들이 넘쳐나기 때문인데요, SSR과 CSR의 차이점에 대한 부분을 모르신다면 꼭 필독!입니다.

NAVER D2

그렇다면 zustand를 알아야 하는데 왜 SSR을 알아야 할까요?

맞아요! 사실 몰라도 괜찮지만, 알면 더 좋지 않나요?

그 이유는 서버쪽에서 데이터를 미리 받은뒤에 그 데이터를 이용해 미리 Document를 생성해 주어야 그 문서를 검색엔진도 Indexing 할 수 있기 때문에 SEO에도 좋고..

사용자 입장에서 새로고침시 누락된 데이터로 인해 깜빡임 현상같은 부분을 방지해 줄 수 있기 때문이죠.

Nextjs에서의 SSR

그중 리액트를 이용해 SSR을 쉽게 구현할 수 있도록 만들어주는 Nextjs는 CSR과 SSR의 장점을 잘 혼합해서 사용자에게 화면을 그려주게 됩니다.

아래 그림과 같이 이해 할 수 있을 것 같습니다.

SSR관련 아무 작업을 안한 결과와, 서버에서 미리 데이터를 받는 getServerSideProps를 사용한 상황으로 사용자가 현재 화면을 새로고침 했을 경우를 한번 비교 해보겠습니다.

CASE1 - Nextjs에서 SSR관련 작업없이 새로고침

새로고침을 하게되면, Next서버에서 문서를 그리게 되는데, 이때 state값이 없기 때문에 예외처리 했던 결과로 문서가 만들어지게 된후 사용자의 브라우저로 다시 전송해주게 됩니다.

Nextjs없이 React를 사용하게 되면 서버에서 처음 한번만 빈 문서를 보내주는 것과 차이가 있습니다.

이후 사용자의 브라우저로 문서가 전송되면 보통 useEffect()와 같은 hooks안에 작성한 API서버로 데이터를 요청하는 작업을 실행하게 되는데, 위 상황에서는 비교적 데이터가 가벼운 유저정보가 먼저 받아와져 로그인은 되었지만, 비디오는 아직 로딩상태인 모습입니다.

💡 hooks안에 있는 API 서버로 데이터를 요청하는 작업 이전에 검색엔진봇의 크롤링이 진행되기 때문에 SEO를 위해 SSR을 선택하는 것이 효과적인 부분이 있습니다.

마지막으로 모든 데이터가 채워져 기존화면과 같은 모습이 만들어지게 됩니다.

그렇다면 서버사이드에서 API서버로 데이터를 요청해 서버에서 컴포넌트로 전달해주는 getServerSideProps를 사용한 상황은 어떻게 진행이 될까요?

CASE2 - getServerSideProps를 사용해 주었을때

새로고침을 하게되면, 서버에서 다시 문서를 그리게 되는데, 이때 getServerSideProps에 작성한 로직을 실행해 주게 됩니다. 만약 아래와 같은 코드로 작성했다고 가정해 볼까요?

export const getServerSideProps = async () => {
// getRedisValue는 API서버로 user-storage키에 해당하는 값을 요청하고 전달받습니다.
  const store = await getRedisValue('user-storage');
  return {
    props: {
      initialUserStore: store ? JSON.parse(store).state : null,
    },
  };
};

API서버에 Redis에 캐싱된 값을 전달받아 props로 전달해주는 로직입니다.

이때 return해준 props는 _app.tsxAppProps로 전달받을 수 있기때문에 reduxzustand와 같은 store에도 전달받은 데이터를 이용해 store를 만들어 줄 수 있습니다.

위 과정이 Nextjs의 서버사이드에서 이루어지기 때문에 서버에서 완성된 상태값을 이용해 데이터를 문서에 그려주고 완성된 문서를 브라우저에 전달하게 됩니다.

브라우저는 완성된 문서를 전달받았기 때문에 별도의 API서버로의 데이터 요청 없이 이미 완성된 문서를 사용자에게 바로 보여줄 수 있게 됩니다.

💡 하지만 서버에서 모든 과정을 처리하고 문서를 받기때문에 [새로고침 - document전달]까지의 로딩기간이 조금 더 길어지게 됩니다.
또한 바로 전달받은 문서는 Hydration이 진행되어야 React가 컨트롤 할 수 있게 됩니다. ← [다음글]

사실 Nextjs와 같은 프레임워크는 내부에서 어떤 일들이 일어나는지 알기 쉽지 않지만, 그 과정을 알고난 뒤에는 훨씬 개발을 쉽게 진행할 수 있게 됩니다.

위 코드에서 리턴해준 props를 받아주는 _app.tsx의 코드를 보면 어떻게 활용할 수 있을지에 대한 생각을 더 할 수 있게 되겠죠?

export default function App({ Component, pageProps }) {
	//getServerSideProps에서 return 해준 initialUserStore 값을 이용해 store를 초기화해주는 hooks
  const userStore = useCreateUserStore(pageProps.initialUserStore);
  return (
    <UserProvider createStore={userStore}>
      <GlobalStyle />
      <Component {...pageProps} />
    </UserProvider>
  );
}

위 코드는 zustand에 SSR 적용하기 위해 만든 코드이지만 contextAPI, redux등 여러가지 상태관리를 위한 도구들에 적용할 수 있습니다.

+ SWR에 SSR 적용시키기

zustand를 ssr에 적용한 과정에 앞서서 SWR도 간단한 방법으로 적용할 수 있기 때문에 먼저 확인해 보겠습니다.

공식문서에도 자세하게 설명되어 있지만, 아래 코드를 통해서도 간단하게 이해할 수 있을 것 같습니다.

Next.js와 함께 사용하는 방법 - SWR

**// pages/index.js**
function Page(){
	const { data } = useSWR(['auth', 1], fetcher) ***//['auth',1]이라는 key를 가진 SWR***
	return(
		<div>....</div>
	)
}
...

***/** ip,query등 브라우저에서 함께 전송된 정보가 담긴 context */***
export const getServerSideProps = async (context) => {
***// ex) www.domain.com/?token=abc 주소로 접근시 토근으로 로그인을 요청하고, 정보를 받는다*** 
	const user = await fetchAuth(context.query.token)
  return {
    props: {
      fallback:{
				***// fallback에 SWR키를 이용해 조회한 데이터를 _App으로 전달***
				[unstable_serialize(['auth',1])]: user, 
			},
    },
  };
};
**// _App.js**
export default function App({ Component, pageProps }: _AppProps) {
  return (
		***// pageProps.fallback으로 넘어온 데이터를 SWR에 주입해준다.***
     <SWRConfig value={{ fallback: pageProps.fallback }}>
       <GlobalStyle />
       <Component {...pageProps} />
     </SWRConfig>
  );
}

이제 개념적 준비는 끝나.. 지는 않고!!! 사실 하나 더 남아있습니다🙂. 바로 Hydration이라는 것인데,

바로 그 Hydration때문에 이 시리즈를 적어보기로 마음먹었기 때문에, 다음장에서 조금 더 자세하게 알아보도록 하겠습니다.👍

0개의 댓글