React StrictMode에서 log가 왜 두 번 안나오지..!?

우선 StrictMode란?

개발 모드에서 StrictMode가 활성화되면 리렌더링이 두 번 실행된다.

이는 StrictMode의 의도된 동작으로, 리렌더링 과정에서 발생할 수 있는 잠재적인 버그를 조기에 발견하기 위한 장치다.

다만, 비즈니스 코드 작성 중에 디버깅 과정에서 console.log 출력이 예상과 다르게 나타나는 현상이 있었다.

  • 동기 함수의 로그는 한 번만 출력됨
  • 비동기 함수의 로그는 두 번 출력됨

예시 코드

아래는 위 상황을 간단히 표현한 코드이다.

import { useMemo } from 'react';

let num = 0;

function App() {
  useMemo(() => {
    const id = num++;
    console.log(id);
    setTimeout(() => {
      console.log(`${id} in timeout`);
    }, 1000);
  }, []);

  return null;
}

export default App;

 

개발 모드이므로 StrictMode가 동작하는 상황이다.

예상 VS 실제 결과

처음엔 두 번 실행되니 아래처럼 출력될 거라 생각했다.

0  
1  
0 in timeout  
1 in timeout

 

하지만 실제로는 전혀 달랐다.
동기 로그(0)는 한 번만 나오고, setTimeout 내부 로그만 두 번찍힌 것이다.  

실제 결과

원인

처음에는 StrictMode 버그인가? 이벤트 루프 문제인가? 등 여러 가설을 세워봤지만, 결론은 단순했다.

React DevTools에서 제공하는 "중복 로그 제거(Deduplication)" 기능 때문이었다.

strict mode로 인해 추가로 생긴 log을 dedup하는 기능

이 기능이 켜져 있으면 StrictMode로 인해 발생한 중복 로그가 한 번만 표시된다.
(동기 로그는 한 번만 보이고, 비동기 로그는 DevTools가 잡아내지 못해 두 번 찍힌 것이다.)

이 옵션을 끄고 다시 실행하면 예상대로 모든 로그가 두 번 출력된다.

왜 이런 기능이 있을까?

React 팀에서는 “StrictMode가 일부러 두 번 실행하지만, 개발자가 디버깅할 때 혼란스럽지 않도록 콘솔에는 최대한 한 번만 보여주자” 라는 취지로 이 기능을 넣은 것이다.

 


 

리액트를 회사에서 사용한 지도 어느덧 2년이 넘었지만, 여전히 배워야 할 것이 많다는 걸 느낀다.
이번 문제를 마주했을 때는 그동안의 지식이 무너지는 듯했지만, 다행히도 버그가 아닌 기능이었다는 점에서 안도할 수 있었다.
앞으로는 React가 어떻게 log를 dedup하는지 코드까지 직접 분석해보며 더 깊이 이해해보고자 한다.