본문 바로가기

React/이론

[React] 렌더링

이전에 브라우저의 렌더링이 어떤 방식으로 이루어지는 지 알아봤다

이번에는 React에서의 렌더링을 알아보자!

Class 컴포넌트의 LifeCycle

클래스 컴포넌트에서의 LifeCycle에 대한 이미지를 가지고 왔다. 

ComponentDidUpdate, DidMount 등등은 우리가 많이 알고 있는 익숙한 것들이다. 

 

하지만 옆에 Render Phase, Commit Phase에 대해서는 특별하게 들어본 적이 없다. 

React에서의 Render Phase와 Commit Phase가 무엇인지 알아보자 

 

Render Phase

간단하게 말하자면 컴포넌트 함수를 호출해서 React의 Element를 반환하고

새로운 Virtual DOM을 만들어준다. 

 

그리고 최초 렌더링이 아니라면 재조정을 통해서 실제 DOM에서 적용할 변경점을 확인한다.

 

재조정 ( Reconciliation )? 

내부에 있는 기존 Virtual DOM과 변경사항으로 만들어진 Virtual DOM을 비교하는 작업이다. 

 

여기서 중요한 점은 Render Phase에서는 변경점을 확인하는 작업을 진행하는 것이지 

실제 화면의 변경을 말하는 것은 아니다. 

Commit Phase 

Render Phase에서 확인한 변경점을 실제 DOM에 적용하는 단계이다. 

만약 변경이 필요한 부분이 없다면 Commit Phase는 진행하지 않는다. 

 

Render Phase와 Commit Phase를 통해서 useCallback과 React.memo를 알아보자 

useCallback 

import { useEffect, useState } from "react";
import ChildComponent from "./ChildComponent";

const ParentsComponent = () => {
  const [update, setUpdate] = useState(0);
 
  const handleClick = () => {
     console.log(update);
  }
  
  useEffect(() => {
     setTimeout(() => {
        setUpdate(prev + 1)
     },1000)
  },[]);

  return (
    <div>
      <ChildComponent onClick={handleClick} />
    </div>
  );
};

export default ParentsComponent;

테스트 코드를 작성해보았다. 

 

  useEffect(() => {
     setTimeout(() => {
        setUpdate(prev + 1)
     },1000)
  },[]);

1초 뒤에 setUpdate를 통해서 ParentsComponent가 리렌더링이 발생한다. 

리렌더링으로 인해서 handleClick 함수도 다시 만들어지므로 ChildComponent도 새롭게 만들어진다. 

 

이것을 useCallback을 사용해서 다시 생성되지 않게 변경해보았다. 

import { useEffect, useState, useCallback } from "react";
import ChildComponent from "./ChildComponent";

const ParentsComponent = () => {
  const [update, setUpdate] = useState(0);
 
  const handleClick = useCallback(() => {
     console.log(update);
  },[]);
  
  useEffect(() => {
     setTimeout(() => {
        setUpdate(prev + 1)
     },1000)
  },[]);

  return (
    <div>
      <ChildComponent onClick={handleClick} />
    </div>
  );
};

export default ParentsComponent;

 

useCallback을 사용했기 때문에 함수는 새롭게 변경되지 않는다. 

하지만 여전히 자식 컴포넌트의 리렌더링이 발생하는 것을 확인할 수 있다.

그렇다면 useCallback을 사용하더라도 성능상 이점은 아에 없을까? 

그것은 아니다. 

 

useCallback을 통해서 Render Phase는 실행되지만, Commit Phase는 실행되지 않는다. 

왜냐하면 이전 Virtual DOM과 현재 Virtual DOM의 Props 값을 같게 유지했기 때문에 

변화가 없기 때문이다. 

 

그렇다면 Render Phase도 실행시키지 않으려면 어떤 방법을 사용해야 할까? 

 

React.memo

 

React Memo는 컴포넌트의 현재 Props 값과 이전 Props 값을 비교해서 

변화가 있으면 리렌더링, 변화가 없으면 렌더링을 안시키는 기능을 제공한다. 

 

그러므로 useCallback을 통해서 Props의 변화가 없기 때문에 

React memo를 사용하면 Render Phase도 실행되지 않는다. 

 

참고

https://www.youtube.com/watch?v=1YAWshEGU6g&t=640s 

 

https://goidle.github.io/react/in-depth-react-intro/

 

React 톺아보기 - 02. Intro | Deep Dive Magic Code

모든 설명은 v16.12.0 버전 함수형 컴포넌트와 브라우저 환경을 기준으로 합니다. 버전에 따라 코드는 변경될 수 있으며 클래스 컴포넌트는 설명에서 제외됨을 알려 드립니다. 이번 포스트에서는

goidle.github.io

 

반응형

'React > 이론' 카테고리의 다른 글

[React] DOM vs Virtual DOM  (0) 2022.11.08
[React] 브라우저의 렌더링 과정  (0) 2022.11.06
[React] Custom Hook  (1) 2022.10.22
[React] Redux  (1) 2022.10.14
[React] Flux  (1) 2022.10.13