React JS는 왜 사용하는 것일까?

Jocy·2022년 6월 28일
1
post-thumbnail

리액트를 왜 사용할까?

DOM은(Document Object Model) 문서 객체 모델이라고 하고 XML이나
HTML 문서에 접근하기 위한 일종의 인터페이스 입니다.

DOM을 제어하기 위해서는 브라우저의 DOM Selector API를 사용해서
특정 DOM을 선택한 뒤 특정 이벤트가 발생하면 변화를 주게 됩니다.

인터랙션이 자주 발생하고 이에 따라 UI를 처음부터 다 표현하게 되면 많은 오버헤드가 발생하게 됩니다.
규모가 큰 웹 어플리케이션이라면 매우 느려지는 문제가 발생하게 됩니다.
그리고 또한 코드를 잘 짜더라도 DOM을 직접 건드리게 되면서 코드가 난잡해질 수 있습니다.
이러한 문제를 해결하기 위해 리액트가 등장 했습니다.

리액트에서는 Virtual DOM을 사용하여 그 문제를 해결했습니다.

브라우저의 실제 DOM이 아니라 그냥 메모리에 가상으로 존재하는 DOM으로서 JavaScript 객체이기 때문에 실제로 브라우저에서 DOM을 보여주는 것 보다 속도가 훨씬 빠릅니다.
실제 브라우저에 보여지고 있는 DOM과 Virtual DOM을 비교를 한 후 업데이트가 필요한 곳의 UI를
Virtual DOM을 통해서 렌더링합니다. 이를 통하여, "업데이트를 어떻게 할 지" 에 대한 고민을 하지 않으면서 빠른 성능도 지켜낼 수 있게 되었습니다.

어떻게 리액트는 비교할 곳을 빠르게 찾아서 바꿔줄 수 있을까요?

하나의 트리를 가지고 다른 트리로 변환하기 위한 최소한의 연산 수를 구하는 알고리즘은
n개의 엘리먼트가 있는 트리에 대해 O(n3)의 복잡도를 가진다고 합니다.

재조정(Reconciliation)

휴리스틱 알고리즘으로 해결

그래서 리액트는 아래의 두 가지 가정을 기반하여 O(n)복잡도휴리스틱 알고리즘을 구현했습니다.
휴리스틱에 의존하고 있기 때문에 가정에 부합하지 않는 경우 성능이 나빠질 수 있습니다.

  1. 서로 다른 타입의 두 엘리먼트는 서로 다른 트리를 만들어낸다.
  2. 개발자가 key prop을 통해, 어떤 자식 엘리먼트가 변경되지 않아야 할지 표시해 줄 수 있다.

Diffing Algorithm

두 개의 트리를 비교할 때, React는 두 엘리먼트의 루트(root) 엘리먼트부터 비교합니다.
이후의 동작은 루트 엘리먼트의 타입에 따라 달라집니다.

1) 엘리먼트의 타입이 다른 경우

// 변경 전
<div><Counter /></div>
// 변경 후
<span><Counter /></span>

두 루트 엘리먼트의 타입을 비교하면서 다르다면 이전 DOM 노드들은 버리고
새로운 DOM 노드들이 DOM에 삽입하여 새로운 트리를 구축합니다.
아래와 같이 변경 전, 후의 코드가 있다면 차이가 있는 곳을 감지하여
Counter는 사라지고 새로 다시 이를 실제 DOM에 패치 시켜줍니다.

2) DOM 엘리먼트의 타입이 같은 경우

//  두 엘리먼트를 비교하면, React는 현재 DOM 노드 상에 className만 수정합니다.
<div className="before" title="stuff" />
<div className="after" title="stuff" />

// style이 갱신될 때, 변경된 속성만을 갱신
<div style={{color: 'red', fontWeight: 'bold'}} />
<div style={{color: 'green', fontWeight: 'bold'}} />

3) 같은 타입의 컴포넌트 엘리먼트

컴포넌트가 갱신되면 인스턴스는 동일하게 유지되어 렌더링 간 state가 유지됩니다.
React는 새로운 엘리먼트의 내용을 반영하기 위해 현재 컴포넌트 인스턴스의 props를 갱신

자식에 대한 재귀적 처리

DOM 노드의 자식들을 재귀적으로 처리할 때, 동시에 두 리스트를 순회하고 차이점이 있으면 변경을 생성합니다. 순차적으로 동일하게 비교가 된다면 성능이 좋겠지만 리스트의 맨 앞이나 중간에 엘리먼트를 추가하는 경우에는 기존에 있는 값과 다르면 삭제,추가를 반복하며 변경된 상태를 유지하게 되어 많은 연산이 필요하게 되어 성능이 좋지 않게 됩니다.

Keys 속성 사용하기

<ul>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

<ul>
  <li key="2014">Connecticut</li>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

재귀적으로 처리할 경우 느려지는 문제를 해결하기 위해, React는 key 속성을 지원합니다.
자식들이 key를 가지고 있다면 key를 통해 기존 트리와 이후 트리의 자식들이 일치하는지
확인하여 효율적으로 변경이 가능하도록 합니다. key는 반드시 변하지 않고, 예상 가능하며,
유일해야 하고 형제 사이에서만 유일하면 되고, 전역에서 유일할 필요는 없습니다.

참고문헌

React 공식문서

profile
Software Engineer

0개의 댓글