Next.js Turbopack dev에서 렌더링이 두 번씩 될 때
dev 실행 시 렌더링/이펙트가 두 번 실행된다?
React Strict Mode
리액트의 StrictMode는 디버그를 위한 몇 가지 기능을 제공해 준다. 그 중에는 이펙트나 렌더링 단계의 버그를 잡기 위해 실행되는 다음과 같은 기능이 이런 문제를 만든다.
- 렌더링 단계에서 발생하는 문제를 찾기 위해 컴포넌트가 한 번 더 렌더링된다.
- 이펙트 정리 누락으로 발생하는 문제를 찾기 위해 이펙트가 재실행된다.
- Deprecated된 API 사용을 탐지한다.
이 중 1번과 2번 때문에 이펙트/렌더링이 두 번씩 실행되는 문제가 발생하게 된다.
발생할 수 있는 문제?
StrictMode는 디버그 단계에서 매우 유용하지만, 간단한 예시로 다음과 같은 코드에서 문제가 발생할 수 있다.
"use client"
import {ReactNode, useEffect, useState} from "react";
export default function ClientComp({children} : {children: ReactNode}) {
const [count, setCount] = useState(0);
useEffect(() => {
setInterval(() => {
setCount(count => count + 1);
}, 1000);
}, []);
return <div>
<h1>Hello, Next.js!!! {count}</h1>
{children}
</div>
}
위 코드는 1초마다 count
를 1씩 증가시키고 이를 표시해주는 컴포넌트이다. 그러나 기본적으로 Next.js의 dev 실행 시 reactStrictMode
가 true
로 설정되어 있으므로, 해당 컴포넌트는 두 번 렌더링되고, 컴포넌트의 이펙트들도 두 번 호출된다.
따라서 useEffect
내부의 setInterval
역시 두 번 호출되게 되어 1초마다 count가 1 증가하는 setInterval이 두 번 호출되므로, 결국 1초마다 count가 2씩 증가하게 된다.
해결 방법
Best Solution?
우선, 가장 좋은 해결책은 당연히 StrictMode가 켜져 있어도 문제가 없게 코딩하는 것이다.
"use client"
import {ReactNode, useEffect, useRef, useState} from "react";
export default function ClientComp({children} : {children: ReactNode}) {
const refInterval = useRef<NodeJS.Timeout>();
const [count, setCount] = useState(0);
useEffect(() => {
refInterval.current = setInterval(() => {
setCount(count => count + 1);
}, 1000);
return () => {
if (refInterval.current) {
clearInterval(refInterval.current);
}
}
}, []);
return <div>
<h1>Hello, Next.js!!! {count}</h1>
{children}
</div>
}
위처럼 cleanup
로직에 올바른 정리 코드를 추가하여 이펙트가 여러번 재호출되더라도 문제가 없도록 작성하는 게 가장 좋다.
위 예제에서는 setInterval
이 무한히 쌓이지 않도록 하기 위해 useRef
를 사용하여 intervalID
를 저장하고, 컴포넌트가 dismount
될 때 이를 정리하는 로직을 추가하였다.
차선책
물론 특수한 상황에서는 이러한 StrictMode를 해제해야 할 수도 있다. React의 경우 <StrictMode>
컴포넌트를 제거하면 되지만 Next.js의 경우 next.config.js
1를 수정해야 한다.
/** @type {import("next").NextConfig} */
const nextConfig = {
reactStrictMode: false,
};
export default nextConfig;
위처럼 설정에서 reactStrictMode
를 false
로 설정해주면 next dev
로 실행하더라도 StrictMode가 작동하지 않게 된다.
또는
next.config.mjs
ornext.config.cjs
↩︎
댓글
댓글 쓰기