ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • React 딥다이브
    프론트엔드 2025. 10. 16. 01:03

    🤔 렌더링이란?

    • 리액트에서 렌더링(Rendering)이란, 컴포넌트 현재의 props state를 기반으로 어떤 UI를 보여줄지 계산하여(가상 DOM 생성), 그 결과를 비교(diff)하고 실제 브라우저 DOM에 반영(commit)하는 전체 과정을 말한다.
    • 만약 컴포넌트의 props, state가 없다면 컴포넌트가 반환하는 JSX값에 기반해 렌더링이 일어나게 된다. 

     

    리액트에서 렌더링이 일어나는 이유

    • 최초 렌더링 : 사용자가 처음 애플리케이션에 접근하면 리액트는 브라우저에 정보를 제공하기 위해 최초 렌더링을 수행한다. 
    • 리렌더링 : 최초 렌더링이 발생한 이후 발생하는 모든 렌더링을 말한다. 
      • 클래스 컴포넌트 setState가 실행되는 경우 : setState 호출을 통해 클래스 컴포넌트에서는 state 변화를 인식하므로 리렌더링이 발생한다. 
      • 함수 컴포넌트의 useState()의 두번째 요소은 setter가 실행되는 경우 : useState가 반환하는 배열의 두번째 인수 또한 setState를 업데이트 하는 함수다. 이 함수가 실행되면 렌더링이 일어난다. 
      • 함수 컴포넌트의 useReducer의 두번째 요소 dispatch가 실행되는 경우 : useReducer도 useState와 마찬가지로 상태와 이 상태를 업데이트하는 함수를 배열로 제공한다. 두 번째 배열요소를 실행하면 컴포넌트의 렌더링이 일어난다
      • 컴포넌트의 key props가 변경되는 경우 : 리액트에서 key는 명시적으로 선언되어 있지 않더라도 모든 컴포넌트에서 사용할 수 있는 특수한 props다. key는 배열에서 하위 컴포넌트를 선언할 때 사용된다. 
      • props가 변경되는 경우 : 부모로 부터 전달받은 props가 달라지면 이를 사용하는 자식컴포넌트에서도 변경이 필요해 리렌더링이 발생한다 
      • 부모 컴포넌트가 렌더링 되는 경우 : 부모 컴포넌트가 리렌더링 된다면 자식 컴포넌트도 무조건 리렌더링이 발생한다
    function TodoList({ todos }) {
      return (
        <ul>
          {todos.map((todo) => (
            <li>{todo.text}</li>
          ))}
        </ul>
      );
    }
    • 위 코드에서 key를 생략하면 콘솔에 경고가 출력된다. 🤔 key는 왜 필요할까 
    • 리액트에서 key는 리렌더링이 발생하는 동안 형제 요소 사이들 사이에서 동일한 요소를 식별하는 값이다. 
    • 동일한 자식 컴포넌트가 있을 때 리렌더링이 발생하면 current 트리와 workInProgress 트리 사이에 어떠한 컴포넌트가 변경이 있엇는지 구별해야 하는데 이 때 사용하는 것이 key다.
    • 이 key로 어느 요소와 같은지 판단하기 때문에 key 값이 변경되면 새로운 값으로 인식해 리렌더링이 발생한다. 

     

    리액트 렌더링 프로세스

    • 리액트에서 렌더링 프로세스가 시작되면 리액트는 컴포넌트의 루트에서부터 차근차근 아래쪽으로 내려가면서 업데이트가 필요하다고 지정돼있는 모든 컴포넌트를 찾는다. 
    • 만약 업데이트가 필요한 컴포넌트를 발견하면 클래스 컴포넌트는 클래스 내부의 render() 함수를 실행하고 함수형 컴포넌트의 경우 FunctionComponent() 그 자체를 호출한 뒤에 결과물을 저장한다. 
    • 렌더링 결과물은 JSX 문법으로 구성되어 있고, 자바스크립트로 컴파일 되면서 React.createElement()를 호출하는 구문으로 변환된다. 
    function Hello() {
      return (
        <TestComponent a={35} b='yceffort'>
          안녕하세요
        </TestComponent>
      ) 
    }
    
    function Hello() {
      return React.createElement(
         TestComponent, 
         {a: 35, b:'yceffort'}
         '안녕하세요'
      )
    }
    • 결과물은 아래와 같이 나온다. 렌더링 프로세스는 위와 같은 과정을 거쳐 컴포넌트의 렌더링 결과물을 수집한 다음, 리액트의 새로운 트리인 가상 DOM과 비교해 실제 DOM에 반영하기 위한 변경 사항을 수집한다. 
    {type: TestComponent, props: {a: '35', b: 'yceffort', children: '안녕하세요'}}

     

    렌더단계, 커밋단계 

    • 리액트 렌더링은 렌더단계와 커밋단계로 나눠서 실행한다. 
    • 렌더단계는 컴포넌트를 렌더링하고 변경 사항을 계산하는 모든 작업을 말한다. 즉 렌더링 프로세스에서 컴포넌트를 실행해 이 결과와 이전 가상 DOM을 비교하는과정을 거쳐 변경이 필요한 컴포넌트를 체크하는 단계이다. 여기서 비교하는 것은 type, props, key다. 
    • 커밋단계는 렌더 단계의 변경사항을 실제 DOM에 적용해 사용자에게 보여주는 과정이다. 이 단계가 끝나야 비로소 브라우저의 렌더링이 발생한다.
    • 리액트가 DOM을 커밋단계에서 업데이트 하면 모든 DOM 노드 및 인스턴스를 가르키드록 리액트 내부의 참조를 업데이트 한다.
    • 그 다음 클래스 컴포넌트의 경우는 componentDidMount, componentDidUpdate 메서드를 호출하고, 함수 컴포넌트에서는 useLayoutEffect 훅을 호출한다.
    • 여기서 알 수 있는 점은 리액트의 렌더링이 일어난다고 해서 DOM 업데이트가 일어나는 것은 아니다. 변경사항이 없다면 커밋단계는 실행이 되지 않는다. 
    function A() {
      return (
        <div className="App">
          <h1>Hello React!</h1>
          <B />
        </div>
      );
    }
    
    function B() {
      const [counter, setCounter] = useState(0);
    
      function handleButtonClick() {
        setCounter((previous) => previous + 1);
      }
    
      return (
        <>
          <label>
            <C number={counter} />
          </label>
          <button onClick={handleButtonClick}>+</button>
        </>
      );
    }
    
    function C({ number }) {
      return (
        <div>
          {number} <D />
        </div>
      );
    }
    
    function D() {
      return <>리액트 재밌다!</>;
    }
    • A,B,C,D라는 컴포넌트가 있다. 리액트가 어떤 순서로 렌더링 되는지 확인해보자
    • 1. B 컴포넌트의 setState가 호출된다. 
    • 2. B 컴포넌트의 리렌더링 작업이 렌더링 큐에 들어간다. 
    • 3. 리액트 트리는 최상단 부터 렌더링 경로를 검사한다.
    • 4. A컴포넌트는 리렌더링이 필요한 컴포넌트로 표시돼 있지 않으므로 별다른 작업을 하지 않는다. 
    • 5. 그다음 하위 컴포넌트인 B 컴포넌트는 업데이트가 필요하다고 체크되어 있으므로 B를 리렌더링 한다. 
    • 6. 5번과정에서 B는 C를 반환한다
    • 7. C는 props인 number가 업데이트 되었으므로 업데이트가 필요한 컴포넌트라고 체크한다
    • 8. 7번 과정에서는 C는 D를 반환했다
    • 9. D도 마찬가지로 업데이트가 필요하지 않다. 하지만 C가 렌더링이 되어 자식 컴포넌트 D도 렌더링이 되었다. 

     

    📘 정리

    React 렌더링은 “함수 실행과 가상 DOM 계산”을 의미하며, DOM 조작은 diff 결과가 있는 경우에만 commit 단계에서 수행된다. 즉, 렌더링이 곧 “화면이 다시 그려진다”는 뜻은 아니다. 

    '프론트엔드' 카테고리의 다른 글

    프로젝트를 하면서 고민점들 (라우팅 렌더링)  (0) 2025.10.18
    React 딥다이브  (1) 2025.10.17
    React 딥다이브  (0) 2025.10.15
    React 딥다이브  (0) 2025.10.15
    Next Image 최적화와 SVG  (0) 2025.10.12
Designed by Tistory.