React.StrictMode와 Render, Commit

진실·2022년 11월 3일

index.tsx에서 App을 렌더링할 때 보면

const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)

이런 식으로 React.StrictMode가 App component를 감싸고 있다.

이거 왜 있는 건가?

React.StrictMode

공식 문서를 봤더니 React.StrictMode는 어플리케이션 내 잠재적인 문제를 알아내기 위한 도구랬다.

즉, 쟤가 버그가 일어날 거 같은 부분을 알아서 먼저 알려주는 거다.

map 함수를 썼을 때 key 안 넣으면 콘솔창에서 난리치던게 쟤 때문이다.

저 strict mode는 다음과 같은 부분을 도와준다고 한다.

console.log가 두 번 찍히는 이유는?

React는 컴포넌트를 렌더링 하기 위해 렌더링, 커밋이라는 두 단계를 거친다.

렌더링 단계에서는 이전과 뭐가 달라졌는지 비교를 한다.

공식 문서를 읽어보면 렌더링은 주방에서 음식을 조리하는 단계, 커밋은 손님에게 음식을 갖다 주는 것에 비유한다.

렌더링은 1. 초기 렌더링, 2. state 업데이트(혹은 부모 컴포넌트의 업데이트) 두 가지로 나뉜다.

초기 렌더링

import Image from './Image.js';
import { createRoot } from 'react-dom/client';

const root = createRoot(document.getElementById('root'))
root.render(<Image />);

이게 초기 렌더링이다.

State update에 따른 재 렌더링

초기 렌더링 후에, state setter 함수 등으로 state에 변화가 일어나면 재 렌더링을 한다.

이때 컴포넌트에 업데이트가 일어나면 렌더링 할 것이 차례대로 큐에 들어간다.

비유를 하자면 레스토랑에서 손님이 처음에 주문을 한 후에 목이 말라서(state 변화) 커피를 시키고(render triggering), 배가 덜 차서(state 변화) 디저트를 주문(render triggering)하는 것이다.

React의 Component rendering

초기 렌더링하는 동안

  • 초기에는 root component부터 쭉 만든다.

재렌더링하는 동안

  • 리액트는 이전 render와 비교해서 바뀐 게 있는 지 확인한다.
  • 바뀐 게 확인 돼도 다음 단계(commit) 전까지는 아무것도 하지 않는다.

변경을 DOM에 “Commit”하는 단계

렌더링 후에는 React가 DOM을 수정한다.

초기 렌더링 후

  • appendChild()를 통해서 DOM 노드를 DOM 트리에 추가

재렌더링 후

  • 렌더링 결과에 따라 최소한의 필수적인 동작만 해서 DOM을 수정함.

React는 render 간의 차이가 있는 노드만 변경한다.

이게 뭔 소리냐?

export default function Clock({ time }) {
  return (
    <>
      <h1>{time}</h1>
      <input />
    </>
  );
}

이렇게 부모 컴포넌트로부터 현재 시각을 전달 받아 화면에 보여주는 코드가 있다고 하자.

그럼 부모 component의 time이 바뀔 때마다 Clock이 재렌더링될 것이다. 근데 input에 글을 써보면 시간이 바뀔때마다 초기화 되야할 것 같은데 그러지 않는다.

WHY????

왜냐하면 commit 단계에서는 render간의 차이가 있는 노드만 변경하기 때문이다. h1 안에 들어가는 time은 달라지지만, input element는 그대로다. 따라서 input은 재렌더링 되지 않는다.

그래서 왜 두 번?

장황하게 리액트의 렌더링 과정에 대해 설명했다.

React.StrictMode로 컴포넌트를 감싸게 되면 원하지 않는 state 변경과 같은 side effect를 방지하고자 저 렌더링 과정이 두 번 수행된다.

따라서 console.log가 두 번 찍히게 되는 것이다.

그럼 끗~

profile
반갑습니다.

1개의 댓글

comment-user-thumbnail
2023년 4월 8일

잘 읽고갑니다!!

답글 달기