Skip to main content

Command Palette

Search for a command to run...

Modern React Deep Dive: 리액트 핵심 요소 깊게 살펴보기

Updated
4 min readView as Markdown
Modern React Deep Dive: 리액트 핵심 요소 깊게 살펴보기
J

Interested in fundamental of web develop

이번 글에서는 리액트를 이루는 근본적인 요소 중 JSX와 가상 DOM, 리액트 파이버 등에 대해 알아봅니다.

JSX란?

JSX란 XML 스타일의 트리 구조로 표현하고 싶은 것들을 자바스크립트와 함께 작성하는 문법입니다. 자바스크립트로 트랜스파일링되어 실행됩니다.

JSX의 구성 요소

  • JSXElement: HTML element와 비슷한 역할을 하는 컴포넌트

  • JSXAttributes: JSXElement에 부여할 수 있는 속성, 필수가 아님

  • JSXChildren: JSXElement의 자식, 0개 이상 존재 가능

  • JSXStrings: 문자열

가상 DOM과 리액트 파이버

리액트의 특징 중 하나는, 실제 DOM을 개발자가 직접 건드리지 않아도 된다는 점입니다.
리액트는 가상 DOM을 운영하여 변경점만을 포착하여 실제 DOM에 반영합니다.
이 과정을 재조정(Reconciliation) 이라고 부릅니다.
가상 DOM은 DOM의 경량화된 복사본 객체입니다.

가상 DOM 탄생 배경

DOM의 모든 변경 사항을 추적하는 것 보다 결과적으로 만들어지는 DOM 결과물을 아는 것이 높은 개발 편의성을 제공해주기 때문입니다.

가상 DOM에 대한 일반적인 오해

많은 사람들이가상 DOM을 통한 DOM 관리가 직접 DOM을 조작하는 것 보다 빠르다고 오해합니다.
하지만 가상 DOM의 diffing, 배치 업데이트 과정에 추가적인 리소스 소모가 있을 수 있습니다.
실제로 직접 DOM을 조작해서 리액트보다 더 빠른 속도를 가진 라이브러리들이 존재합니다. (ex: Svelte, Solid.js)
가상 DOM의 이점은 상태 변경에 따라 전체 UI를 새로 그리는 것 처럼 개발할 수 있으나 실제 DOM 반영은 일부만 되는 것과, 컴포넌트 트리를 가상 DOM이란 레이어로 추상화하여 실제로 그리는 렌더러를 바꿀 수 있는 것에 있습니다.

dan abramov: 가상 DOM은 무조건 빠른 것이 아니라 대부분의 상황에 웬만한 애플리케이션을 만들 정도로 충분히 빠르다.


리액트 파이버

리액트에서 관리하는 객체. 하나의 태그와 1:1 매칭되고 가상 DOM과 실제 DOM의 차이, 변경점을 수집하여 차이가 있을 시 렌더링을 요청하는 역할입니다.

React 16 버전 이전에는 재조정 알고리즘이 동기적인 스택 알고리즘으로 작동했습니다.
동기적으로 동작하면서 발생하는 인터랙션의 반응성 문제를 해결하는 것이 리액트 파이버의 목표였습니다.
따라서 리액트 파이버는 비동기적으로 작동하고, 작업을 멈추고 우선순위가 높은 작업을 처리할 수도 있습니다.

파이버의 동작은 렌더 단계와 커밋 단계로 나뉘어져 있습니다.

리액트는 Value UI 라이브러리이다.

리액트는 UI를 값으로 관리하여 변수에 UI 관련 값을 보관하고, 이를 관리하고 표현하는 라이브러리입니다.

파이버는 컴포넌트가 최초로 마운트되는 시점에 생성되어 가급적이면 재사용됩니다.

리액트 파이버 트리

리액트 파이버 트리는 현재의 모습을 담은 current 파이버 트리와 작업중인 상태를 나타내는 workInProgress 트리가 있습니다.
리액트 파이버의 작업이 끝나면 트리를 가리키는 포인터만 변경해 workInProgress 트리를 current 트리로 바꿔치기합니다. 이런 기법을 더블 버퍼링이라고 하는데, 컴퓨터 그래픽스에서 사용하는 용어로 보이지 않는 곳에서 다음 그려야 할 그림을 그린 후 그림이 완성되면 현재 상태를 새로운 그림으로 바꾸는 것입니다. 리액트에서 더블 버퍼링은 커밋 단계에서 수행됩니다.

파이버 동작 방식

  1. setState 등으로 업데이트가 발생하면 workInProgress 트리를 빌드하여 상태가 변경된 부분을 반영 (렌더 단계)

  2. 이를 react-dom 혹은 React Native 내부의 렌더러 등이 실제 렌더링 (커밋 단계)

알고 넘어갈 점
리액트 파이버와 DOM/네이티브 렌더링은 별개입니다.
따라서 렌더러가 다르다 하더라도 동일한 재조정자를 사용할 수 있습니다.


클래스 컴포넌트, 함수 컴포넌트

리액트에서는 클래스와 함수를 기반으로 컴포넌트를 만들 수 있습니다.
클래스 컴포넌트는 사실상 레거시인데, 다만 생명주기 메소드 중 함수 컴포넌트로 모사 불가능한 것이 필요할 경우 사용이 불가피합니다.

클래스 컴포넌트의 한계 → 함수 컴포넌트의 장점

  • 데이터 흐름을 추적하기 어렵다. → this와 관련된 혼란을 줄이고 Hooks API를 통해 일관된 흐름 유지.

  • 로직 재사용이 어렵다. → 커스텀 훅으로 로직 재사용 가능.

  • 클래스의 한계로 번들 크기 증가 → 사용하지 않는 함수 등을 트리쉐이킹 가능.

  • instance 내부에 state를 관리하여 핫 리로딩에 불리하다. → 리액트 아키텍처 내부 클로저에 state 저장하여 핫 리로딩에 최적화 되어있다.

클래스 컴포넌트 vs 함수 컴포넌트

클래스 컴포넌트는 props, state의 값을 항상 this로부터 가져온다. (mutable하여 렌더링 이후에 변경된 값을 읽을 수 있음)
함수 컴포넌트는 props를 함수의 인자로 받고, 컴포넌트가 그 값을 변경할 수 없다. (렌더링이 일어난 순간의 값을 참조)


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

리액트의 렌더링이란 컴포넌트들이 지닌 state와 props의 값을 기반으로 UI의 구성을 결정하고 어떤 DOM 결과를 브라우저에 제공할지 계산하는 과정입니다.

리액트에서 렌더링이 발생하는 시나리오

  1. 최초 렌더링: 처음 애플리케이션에 진입했을 시 화면을 그려야 합니다.

  2. 리렌더링: state 업데이트, key prop 변경 시 업데이트 된 상태에 따라 UI 또한 업데이트 됩니다.

렌더링 프로세스

상태 변경을 감지하고, 변경된 상태를 기반으로 새로운 가상 DOM을 생성한 후, 실제 DOM에 변경된 결과물을 반영합니다.

렌더 단계

컴포넌트를 실행하여 그 결과와 이전 가상 DOM을 비교하여 변경이 필요한 컴포넌트를 체크하는 단계.

커밋 단계

렌더 단계의 변경 사항을 실제 DOM에 적용하는 단계. (렌더 단계에서 변경 사항이 없다면 실행되지 않습니다.)


메모이제이션

리액트에서 React.memo, useMemo, useCallback은 각각 컴포넌트, 값, 함수를 메모이제이션하는 기능입니다.

메모이제이션은 성능 최적화를 위한 기술이지만 거기에도 비용이 들며, 두 가지 관점에서 갑론을박이 벌어지는 중입니다.

주장1: 메모이제이션은 꼭 필요한 곳에만

메모이제이션은 값을 어딘가에 저장해두어야 하기 때문에 리소스가 추가로 들고, 성능에 영향이 미미한 작업까지 메모이제이션 할 필요는 없다는 관점입니다.

주장2: 모조리 메모이제이션

모든 것을 메모이제이션 하는 비용보다 필요한 곳에 메모이제이션이 적용되지 않았을 때 드는 비용이 훨씬 크므로 메모이제이션을 적용할 곳을 선별하지 말고 모두 메모이제이션하자는 관점입니다.

More from this blog

Vanilla SPA 1: JSX & Virtual DOM Diffing

대망의 나만의 리액트 스타일 SPA 만들기 시작해보겠습니다. 이번 아티클에서는 JSX 파싱 JSX to Virtual DOM Virtual DOM Diffing Commit 을 다뤄보도록 하겠습니다. JSX란? JSX란 XML 스타일의 트리 구조로 표현하고 싶은 것들을 자바스크립트와 함께 작성하는 문법입니다. JSX의 구성 요소 JSXElement: HTML element와 비슷한 역할을 하는 컴포넌트 JSXAttributes: ...

Feb 23, 20245 min read
Vanilla SPA 1: JSX & Virtual DOM Diffing

Typescript: unknown과 any의 차이

타입스크립트의 타입 시스템을 공부하다 문득 unknown도 모든 타입 다 들어가고 any도 다 들어가는데 뭐가 다른거지? 라는 생각이 들어서 무슨 차이가 있는지 찾아보았다. unknown 사용시(프로퍼티에 접근 시, 연산 시) 타입을 지정해주어야 함 다른 타입에 할당 불가능 타입의 가능성을 열어뒀다가 좁히는 용도로 사용 any 나는 타입이길 포기한다

Jan 23, 20241 min read
Typescript: unknown과 any의 차이

모든 웹 개발자가 관심을 가져야 할 핵심 웹 지표

Core Web Vitals 구글에서 만든 것으로 웹페이지의 성능을 평가하는 지표들. LCP Largest Contentful Paint 페이지 로딩 성능을 의미하는 것. 의미 정확히는 '페이지가 처음으로 로드를 시작한 시점부터 뷰포트 내부에서 가장 큰 이미지 또는 텍스트를 렌더링하는 데 걸리는 시간' 뷰포트란?사용자에게 현재 노출되는 화면. 기기마다 다르다. '큰 이미지와 텍스트'는 아래의 요소들을 뜻한다. <img> <svg> 내부의...

Jan 5, 20242 min read
모든 웹 개발자가 관심을 가져야 할 핵심 웹 지표

Modern React Deep Dive: 리액트 17, 18 변경사항

현재 인터넷에서 가장 많이 쓰이는 리액트 버전은 16 버전이다. 그 이후 버전인 17, 18 버전에서 어떠한 변화가 있었는지 살펴보자. 리액트 17 버전 리액트 17 버전은 새롭게 추가된 기능이 없으며 기존 코드의 수정을 필요로 하는 변경 사항이 최소화되어있다. 이전 버전과의 호환성을 중시하며 17 버전으로 이동하기 쉽도록 만들어져 있다. 이벤트 위임 방식 변경 이전 버전에서는 이벤트 핸들러가 문서의 루트(Document)에서 이벤트를 캐치했지...

Dec 31, 20234 min read
Modern React Deep Dive: 리액트 17, 18 변경사항

Modern React Deep Dive: 서버 사이드 렌더링

서버 사이드 렌더링 서버 사이드 렌더링(SSR)이란 웹 애플리케이션의 컨텐츠를 서버에서 렌더링하는 기법을 말한다. SSR에 대해 알아보기 전에 기존의 프론트엔드 중심 개발 방법 중 하나인 싱글 페이지 애플리케이션(SPA)를 알아본다. 싱글 페이지 애플리케이션(SPA) 과거엔 자바스크립트로 할 수 있는 일이 제한적이라 대부분의 처리를 서버에서 해야 했다. (데이터 연동, 페이지 렌더링, 인증/인가 로직 등)그 구조로 인해 관심사의 분리가 덜 이루...

Dec 6, 20232 min read
Modern React Deep Dive: 서버 사이드 렌더링

얼렁뚱땅 알잘딱깔센 개발 라이프🙌

9 posts

문의는 DM으로 부탁드려요🙏