React, Next.js, TypeScript 프로젝트에서 Disqus 통합하기
무료로 내 홈페이지에 댓글 기능을 만들 수 있는 디스커스는 정말 좋은서비스 입니다만.... React, Next.js, TypeScript 프로젝트에서 Disqus를 통합할 때 가장 흔히 발생하는 문제 중 하나가 바로 hydration 에러다. hydration 에러는 서버에서 렌더링된 HTML과 클라이언트에서 실행되는 React의 가상 DOM이 일치하지 않을 때 발생하는데, 이를 해결하지 않으면 페이지가 깨지거나 예기치 않은 동작이 발생할 수 있다.
1. hydration 에러의 원인
Disqus는 기본적으로 클라이언트 사이드에서 동적으로 스크립트를 삽입하고, 이를 통해 댓글을 불러오는 방식이다. 그런데 Next.js와 같은 서버 사이드 렌더링(SSR) 환경에서 dangerouslySetInnerHTML
을 사용하여 Disqus 코드를 삽입하면, 서버에서 생성된 HTML과 클라이언트에서 실행되는 HTML이 달라져 hydration 에러가 발생할 가능성이 높다.
2. 해결 방법
이 문제를 해결하기 위해 사용할 수 있는 몇 가지 방법을 소개한다.
(1) disqus-react 라이브러리 사용
Disqus를 React 컴포넌트로 쉽게 사용할 수 있도록 도와주는 disqus-react
라이브러리를 활용하면, hydration 에러를 방지할 수 있다.
import { DiscussionEmbed } from 'disqus-react';
const DisqusComments: React.FC = () => {
return (
<DiscussionEmbed
shortname='your-disqus-shortname'
config={{
url: window.location.href,
identifier: 'unique-page-identifier',
title: 'Page Title',
}}
/>
);
};
이 방법은 가장 간단하면서도 효과적인 해결책이다. 하지만 만약 disqus-react
가 예상대로 동작하지 않거나, 추가적인 커스터마이징이 필요하다면 다른 방법을 고려해야 한다.
(2) useEffect를 사용한 클라이언트 사이드 스크립트 로딩
Disqus 스크립트를 클라이언트 사이드에서만 동적으로 삽입하면, 서버와 클라이언트 간의 HTML 불일치를 방지할 수 있다.
import { useEffect } from 'react';
const DisqusComments: React.FC = () => {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://your-shortname.disqus.com/embed.js';
script.setAttribute('data-timestamp', Date.now().toString());
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
};
}, []);
return <div id="disqus_thread"></div>;
};
이 방법을 사용하면 hydration 에러를 방지할 수 있지만, useEffect
의 동작 특성상 초기 렌더링 시점에서는 Disqus가 보이지 않다가 이후에 로딩되는 문제가 있다.
(3) 클라이언트 사이드 렌더링 (CSR) 사용
Next.js에서는 dynamic
함수를 이용해 특정 컴포넌트를 클라이언트 사이드에서만 렌더링하도록 설정할 수 있다.
import dynamic from 'next/dynamic';
const DisqusComments = dynamic(
() => import('../components/DisqusComments'),
{ ssr: false }
);
const Page: React.FC = () => {
return (
<div>
<h1>Page Content</h1>
<DisqusComments />
</div>
);
};
이 방법을 사용하면 Disqus 컴포넌트는 서버에서 렌더링되지 않고, 클라이언트에서만 로딩되므로 hydration 에러가 발생하지 않는다.
(4) suppressHydrationWarning 사용
<div suppressHydrationWarning={true}>
속성을 추가하면 특정 요소에서 hydration 경고를 억제할 수 있다.
<div suppressHydrationWarning={true}>
<div id="disqus_thread"></div>
</div>
하지만 이 방법은 근본적인 문제를 해결하지 못하며, 단순히 경고를 숨기는 역할만 하기 때문에 가급적 다른 해결책을 먼저 고려하는 것이 좋다.
3. 결론
Disqus를 React, Next.js, TypeScript 환경에서 사용할 때 가장 추천하는 방법은 disqus-react
라이브러리를 사용하는 것이다. 만약 이 방법이 맞지 않는다면 useEffect
를 활용한 동적 스크립트 로딩이나 Next.js의 dynamic
을 사용한 클라이언트 사이드 렌더링을 고려하는 것이 좋다. suppressHydrationWarning
은 최후의 수단으로만 활용해야 한다.
결론적으로, Disqus는 클라이언트 사이드에서만 동작하도록 처리해야 한다. 그렇지 않으면 Next.js의 SSR과 충돌하여 hydration 에러를 유발할 가능성이 높다. 위에서 소개한 해결책을 활용하면 Next.js 프로젝트에서도 안정적으로 Disqus를 사용할 수 있을 것이다.