[React] Error: ReactDOMServer does not yet support Suspense.

devstone·2022년 3월 3일
1

에러 해결기

목록 보기
2/2
post-thumbnail

React와 webpack으로 SSR이 구현된 코드베이스에서 React.Suspense 컴포넌트를 사용하려다가 위와 같은 에러를 마주하였다.

import React, { useState, Suspense } from 'react';
import styles from './style.scss';
import GetData from './components/GetData';
import ErrorBoundary from './asyncHandler/ErrorBoundary';
import ErrorComponent from './asyncHandler/ErrorComponent';
import LoadingComponent from './asyncHandler/LoadingComponent';
import SSRCompatibleSuspense from './asyncHandler/SSRCompatibleSuspense';

function AsyncTest() {
	return (
        <ErrorBoundary renderFallback={({ error }) => <ErrorComponent error={error} />} resetKey={resetKey}>
            <Suspense fallback={<LoadingComponent />} >
                <GetData />
            </Suspense>
        </ErrorBoundary>
	);
}

export default AsyncTest;

문제의 원인은 React로 SSR을 구현하기 위해 사용한 ReactDOMServer.renderToString 에서 Suspense 컴포넌트를 지원하지 않았기 때문이었다.

참고로 ReactDOMServer.renderToString 는 React 엘리먼트의 초기 HTML을 렌더링하며 HTML 문자열을 반환시킨다. 이렇게 서버사이드에서 렌더링 된 마크업이 있는 노드에서는 ReactDOM.hydrate()를 호출해 위의 마크업을 보존하고 이벤트 핸들러만 연결함으로써 첫 로드 성능을 향상시킬 수 있다.

그럼 이 문제를 어떻게 해결하면 좋을까 ?
Suspense컴포넌트를 커스텀해서 서버사이드환경에선 전달받은 fallback 컴포넌트를 렌더링 할 수 있도록, 클라이언트사이드 환경에선 Suspense 컴포넌트를 적용시키도록 Suspense컴포넌트 불러오는 시점이 페이지가 마운트 된 이후가 되도록 커스텀을 해보았다.

  • SSRCompatibleSuspense.jsx
import React, { Suspense } from 'react';
import useMounted from 'hooks/useMounted';

export default function SSRCompatibleSuspense(props) {
    const isMounted = useMounted();

    if (isMounted) {
        return <Suspense {...props} />;
    }
    return <>{props.fallback}</>;
}
  • useMounted.js
import React from 'react';

function useMounted() {
    const [mounted, setMounted] = React.useState(false);

    React.useEffect(() => {
        setMounted(true);
    }, []);

    return mounted;
}

export default useMounted;
  • AsyncTest.jsx
import React, { useState } from 'react';
import styles from './style.scss';
import GetData from './components/GetData';
import ErrorBoundary from './asyncHandler/ErrorBoundary';
import ErrorComponent from './asyncHandler/ErrorComponent';
import LoadingComponent from './asyncHandler/LoadingComponent';
import SSRCompatibleSuspense from './asyncHandler/SSRCompatibleSuspense';

function AsyncTest() {
	return (
        <ErrorBoundary renderFallback={({ error }) => <ErrorComponent error={error} />} resetKey={resetKey}>
            <SSRCompatibleSuspense fallback={<LoadingComponent />} >
                <GetData />
            </SSRCompatibleSuspense>
        </ErrorBoundary>
	);
}

export default AsyncTest;

이를 통해 위 에러를 해결할 수 있었다! 동일한 에러에 대해 라이브러리나 프레임워크의 config를 이용해 해결할 수도 있었을 것 같은데, 순수 React로 SSR을 구현한 해당 프로젝트에서는 위와 같은 방식으로 에러를 해결하였다.

profile
개발하는 돌멩이

0개의 댓글