React - 재조정(Reconciliation)

이호현·2020년 11월 21일
0

React

목록 보기
5/13

Reactrender될 때마다 특정 알고리즘을 이용해 DOM 트리를 비교해서 반영하는걸로 보인다.
그 비교 알고리즘을 공식 문서를 통해 정리해 보려고 한다.
예제 코드의 대부분은 공식 문서에서 가져왔다.

1. 비교 알고리즘

두 개의 트리를 비교할 때, React는 두 엘리먼트의 루트(root) 엘리먼트부터 비교합니다. 이후의 동작은 루트 엘리먼트의 타입에 따라 달라집니다.
이렇게 적혀있는데 두 개의 트리는 아마 Real DOMVirtual DOM을 말하는거라고 생각함.

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

두 개의 엘리먼트 타입이 다를 경우 이전에 있던 트리를 모두 새로운 트리로 바꾼다.

<div>
  <p>변경 전</p>
<div>

를 아래와 같이 바꾼다면

<span>
  <p>변경 후</p>
<span>

divspan으로 바꾸고 ptext를 변경하는게 아니라 기존의 div하위 트리가 모두 UnMount되고 span과 하위 트리가 다시 Mount되는 방식이다.
LifeCycle은 트리가 삭제되면서 componentWillUnmount()가 실행되고 새로운 트리가 만들어질 때 componentWillMount()가 실행되고 componentDidMount()가 실행된다.

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

두 엘리먼트의 속성만 비교하여 다른 부분만 변경한다.

<div className='before' style={{color: 'red', fontWeight: 'bold'}} ></div>
<div className='after' style={{color: 'green', fontWeight: 'bold'}} ></div>

위와 같은 경우 변경 된 classNamestyle 속성 안의 color만 변경되서 적용된다.

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

state는 그대로 유지하고, props는 갱신한다.
LifeCyclecomponentWillReceiveProps()componentWillUpdate()가 실행된다.





2. 자식에 대한 재귀적 처리

DOM 노드의 자식들을 재귀적으로 처리할 때, React는 기본적으로 동시에 두 리스트를 순회하고 차이점이 있으면 변경을 생성합니다.

1) key가 없는 경우

<ul>
  <li>first</li>
  <li>second</li>
</ul>
<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>

변경 전 트리의 마지막에 자식 요소를 추가하면 자식요소를 처음부터 비교하면서 마지막에 추가된 것만 변경됐다고 인식한다.

<ul>
  <li>Duke</li>
  <li>Villanova</li>
</ul>
<ul>
  <li>Connecticut</li>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

그러나 위와 같이 마지막이 아닌 위치에 자식 요소가 추가되면 차이가 발생한 요소부터 트리를 지우고 다시 추가하는 작업을 하는걸로 보인다.

2) key가 있는 경우

요소들에 key라는 서로를 식별할 수 있는 고유값을 부여하면 위와 같은 현상을 방지할 수 있다.

<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>

key값이 있다면 위치와 상관없이 key를 비교해서 변경 사항을 인식하기 때문에 key가 없을 때와는 달리 마지막 요소에 추가되는게 아니라도 효율적인 작업을 할 수 있다.
key는 형제 요소 사이에서만 식별할 수 있으면 되기 때문에 전역에서 관리할 필요가 없다.
(중요)
배열의 경우 indexkey로 사용할 수 있는데 이럴 경우는 요소의 변경이 없을 경우에는 가능한 방법이다.
요소의 위치가 바뀔 때 문제가 발생할 수 있다.
EX) ['개', '고양이', '곰']index를 사용할 때

<div key='0'></div>
<div key='1'>고양이</div>
<div key='2'></div>

이런 식으로 될 텐데 요소의 위치가 바뀌어서 ['고양이', '곰', '개']가 된다고 하면

<div key='0'>고양이</div>
<div key='1'></div>
<div key='2'></div>

그 요소가 가지고 있던 고유 key값이 계속 바뀔수가 있어서 state관리에 문제가 생길 수 있다.





3. 고려 사항

1. 알고리즘은 다른 컴포넌트 타입을 갖는 종속 트리들의 일치 여부를 확인하지 않습니다. 만약 매우 비슷한 결과물을 출력하는 두 컴포넌트를 교체하고 있다면, 그 둘을 같은 타입으로 만드는 것이 더 나을 수도 있습니다. 우리는 실제 사용 사례에서 이 가정이 문제가 되는 경우를 발견하지 못했습니다.

  • 내용 자체가 확 와닿지 않는데 통채로 UnMount시키는 상황을 만들지 말라는거 같다.

2. key는 반드시 변하지 않고, 예상 가능하며, 유일해야 합니다. 변하는 key(Math.random()으로 생성된 값 등)를 사용하면 많은 컴포넌트 인스턴스와 DOM 노드를 불필요하게 재생성하여 성능이 나빠지거나 자식 컴포넌트의 state가 유실될 수 있습니다.

  • key를 사용할 때 확실히 사용가능한 값을 써야된다는 얘기 같다.
profile
평생 개발자로 살고싶습니다

0개의 댓글