[Next.js] 렌더링 원리

종인·2023년 4월 17일
0

렌더링 과정

브라우저가 프론트엔드 서버에서 HTML, CSS, JavaSctipy 파일을 받기 전에 프론트엔드 서버에서 먼저 HTML, CSS, JavaSctipy 파일을 그려본다. 이 과정을 Pre-rendering이라 한다. 그 후 브라우저는 프론트엔드 서버로부터 HTML 파일을 받고 렌더링하는데 이때 브라우저에서 렌더링 한 내용과 프론트엔드 서버에서 렌더링한 내용이 서로 다른지 비교한다. 이 과정을 ㅇDiffing이라고 한다. Diffing을 진행한 후 최종적으로 렌더링 하게 되는데 이 과정을 Hydration이라 한다.

렌더링 문제점

_app.tsx

const ApolloSetting = ({ children }: IApolloSettingProps) => {
	const [accessToken, setAccessToken] = useRecoilState(accessTokenState);

	// 렌더링 과정에서 오류 발생 (프론트엔드 서버에는 window가 없다.)
	const result = localStorage.getItem("accessToken");
	if (result) setAccessToken(result);

	return (
    	<ApolloProvider client={client}>
        	{children}
      	</ApolloProvider>
  	);
};

export default ApolloSetting;

위 같은 과정의 렌더링을 하기 때문에 Pre-rendering 과정에서 window가 없는 프론트엔드 서버에서 위 코드는 오류를 발생시킨다.

해결책

따라서 브루우저와 프론트엔드 서버에서의 렌더링을 분리해 줘야 한다. 방법은 다음과 같다.

1. process.browser 방법

  if (process.browser) {
    console.log("브라우저 렌더링");
    const result = localStorage.getItem("accessToken");
    if (result) setAccessToken(result);
  } else {
    console.log("프론트엔드 서버 렌더링(yarn dev로 실행시킨 프로그램 내부)");
    const result = localStorage.getItem("accessToken");
    if (result) setAccessToken(result);
  }

2. typeof window 방법

  if (typeof window !== "undefined") {
    console.log("브라우저 렌더링");
    const result = localStorage.getItem("accessToken");
    if (result) setAccessToken(result);
  } else {
    console.log("프론트엔드 서버 렌더링(yarn dev로 실행시킨 프로그램 내부)");
    const result = localStorage.getItem("accessToken");
    if (result) setAccessToken(result);
  }

3. useEffect 방법

  useEffect(() => {
    console.log("브라우저 렌더링");
    const result = localStorage.getItem("accessToken");
    if (result) setAccessToken(result);
  }, []);

이 방법에서는 프리렌더링을 무시한다. (componentDidMount 시점)

결과

const ApolloSetting = ({ children }: IApolloSettingProps) => {
	const [accessToken, setAccessToken] = useRecoilState(accessTokenState);

	useEffect(() => {
    	console.log("브라우저 렌더링");
    	const result = localStorage.getItem("accessToken");
    	if (result) setAccessToken(result);
  	}, []);

	return (
    	<ApolloProvider client={client}>
        	{children}
      	</ApolloProvider>
  	);
};
profile
어쩌면 오늘 하루는

0개의 댓글