[React] Virtual DOM, key

2024. 5. 22. 17:47카테고리 없음

[1] 가상 돔 (Virtual Dom)

 

 

DOM : (Documnet object model)

웹페이지에 들어가 있는 html element 들을 tree형태 구조로 표현한 것
DOM이 제공하는 API를 통해 DOM 구조에 접근하고, 원하는 Element에 구조,내용,스타일을 변경 가능 (DOM 조작)
자바스크립트 getElementById(), querySelector() 같은 API를 통해서 DOM구조 안에 있는 Element에 접근해서 원하는대로 내용,스타일,레이아웃등을 수정할 수 있음.

가상돔 (Virtual Dom)

 

실제 DOM의 복사본 (실제 DOM X)
모든 Elemnet와 속성을 똑같이 가지고 있음
실제 DOM과는 다르게 브라우저 문서에 직접적으로 연결 X => 수정 X

React는 가상 DOM을 똑똑하게 사용하여 시간을 획기적으로 줄여줌


DOM 조작 
=>  브라우저가 현재 페이지에 html 탐색, 해당 엘리먼트를 찾고 해당 엘리먼트와 자녀 엘리먼트들을

DOM에서 제거,새롭게 수정된 Elemnet들로 교체
CSS를 다시 계산하고 레이아웃 정보를 알맞게 수정하고 새롭게 계산된 내용에 따라서 브라우저에 다시 그려줌.

=> DOM은 Tree 구조이기에 Tree에 있는 정보를 업데이트 시켜주는 것은 무거운 작업은 아님
=> 빠른 알고리즘을 사용해서 Tree를 효율적으로 업데이트 시켜줄 수 있기 떄문
매번 DOM을 조작할때마다 브라우저 화면에 UI를 새롭게 그려주는 작업은 꽤나 복잡하고 시간이 걸리는 작업
예를 들어 리스트의 5개 항목의 스타일을 따로 변경해야한다면 시간이 걸림(비효율적)

 

가상돔은 이러한 부분을 해결

실제돔과 다르게 직접적으로 화면에 보이는 UI를 조작할 수 있게 해주는 API를 제공해주지 않음.
가상돔은 메모리에 저장되어 있는 자바스크립트 객체에 불과
그렇기에 가상 돔을 생성하고 접근하는 것은 아주 가볍고 빠른 작업 => (실제 브라우저화면에 접근하는것이 X)


React는 어떻게 가상돔을 활용하여 보다 더 효율적으로 실제 DOM을 조작할까?

React는 항상 2개의 가상 돔 객체를 가지고 있음 
첫번째 가상돔은 렌더링 이전에 화면 구조를 나타내는 가상돔
두번째 가상돔은 렌더링 이후에 보이게될 화면 구조를 나타내는 가상돔

리액트는 state가 변경될때마다 화면이 새로 렌더링이 됨.
(실제 브라우저에 그려지기 이전에)  리액트는 렌더링이 발생될 상황에 놓일때마다 새로운 화면에 들어갈 내용이 담긴 가상돔 생성

그래서 첫번째 가상돔과 업데이트 이후의 내용을 담고있는 두번째 가상돔을 비교해서 정확히 어느 엘리먼트들이 변했는지 찾아냄.


이러한 과정을 "Diffing"
Diffing은 효율적인 알고리즘을 사용해서 진행되기 때문에

정확히 어느 엘리먼트들이 변경되었는지 굉장히 빠르게 파악할 수 있음.
바뀐 엘리먼트들을 파악한 다음에 리액트는 바뀐 부분들만 실제 DOM에 적용시켜 줌
바뀐 엘리먼트들만 실제 브라우저 화면에 적용시킴 = (Reconciliation : 재조정)


리액트에 재조정 과정이 효율적인 이유는 "batch update
Batch Update : (집단,무리) 업데이트 => 변경된 모든 엘리먼트들을 집단으로 실제 DOM에 한번에 적용시켜 주는 것
EX>만약 리스트안에 10개의 항목이 바뀌었다면 실제 DOM을 10번 반복하여 조작하는게 아닌 
한꺼번에 바뀐 모든 부분들을 집단으로 적용시켜 주는 것
DOM조작에 있어서 가장 비용이 많이 드는 작업은 화면을 그려주는 작업
batch update는 변경된 엘리먼트를 하나하나 따로 그려주는게 아닌 변경된 내용을 한번에 다 받아와서 실제 DOM에 한꺼번에 적용시켜주는것 => 훨씬 빠르고 효율적

정리
1. 리액트의 가상돔은 실제 DOM과 같은 내용을 담고 있는 복사본
그리고 이 복사본은 자바스크립트 객체 형태로 메모리상에 저장

2. 리액트는 항상 두 개의 가상돔을 갖고 있다. 첫번째는 가상돔은 변경 이전의 내용을 담고
두번째 가상돔은 변경 이후에 보여질 내용을 담고 있음.

3. 변경된 내용이 화면에 새롭게 그려지기 이전, 곧 실제 DOM이 변경되기 이전에 
리액트는 두 개의 가상돔을 비교해서 정확히 어떤 부분이 바뀌었는지 효율적으로 비교하여 파악 "Diffing"

4. Diffing을 통해서 변경된 부분들을 파악한 이후에, 리액트는 Batch Update를 수행함으로 실제 DOM에 한번에 적용

"Reconsiliation(재조정)"

[2] Key

list : 목록 (프로그래밍 : 같은 아이템을 순서대로 모아놓은것)
list를 위해 사용하는 자료구조는 배열(array)
배열은 자바스크립트의 변수나 객체들을 하나의 변수로 묶어 놓은 것 

React에서는 배열을 사용해 리스트 형태로 엘리먼트들을 렌더링

key? 열쇠라는 의미

열쇠의 특징 : 열쇠는 모두 다 모양이 다르다 열쇠는 각자 고유
=> 열쇠가 고유하지 않으면 가치나 의미가 없음
이로인해 프로그래밍에서의 키는 각 객체나 아이템을 구분할수 있는 고유한 값을 의미

그리고 리액트에서의 키는 리스트에 존재하는 아이템들을 구분하기 위한 고유한 문자열을 의미

(Key는 list에서 아이템이 변경,추가,제거 되었는지 구분하기 위해 사용한다.)

(각 리스트 사이 에서는 Key가 같아도 상관없음!)

Ex> 주민등록번호,학번,핸드폰 번호, 여권번호

 

 

 


React에서는 배열과 키를 사용하여 반복되는 여러개의 컴퍼넌트들을 쉽게 렌더링 가능
엄밀히 말하면 반복되는 다수의 엘리먼트가 렌더링 되는 것

[방법]

A라는 컴포넌트와 B라는 컴포넌트가 반복적으로 나옴 

=> 같은 컴퍼넌트를 화면에 반복적으로 나타날때 코드 상에 하나씩 직접 넣는것은 비효율적(같은 코드가 계속해서 반복, 또한 동적으로 화면에 내용이 바뀌는 경우에는 코드를 직접 하나씩 넣는 방식으로는 구현하기 까다로움) => map() 권장  

map() 함수는 영단어 "mapping" : 한쪽에 있는 아이 템과 다른 아이템을 짝지어 준다는 것을 의미
배열에 들어있는 각 변수에 처리를 한뒤 리턴을 하는 것


리액트에서 key를 권장하는 경우

1. key로 값을 사용하는 경우 : numbers 배열의 숫자들이 중복되지 않는 경우에는 정상적으로 작동하지만,

numbers 배열에 "중복된 숫자가 들어있다면" key값도 중복되기 때문에 고유해야 한다는 key값의 조건이 충족되지 않음

 (key 값이 중복된다는 경고 메시지 출력) 


2. key로 id를 사용하는 경우 : id 의미 자체가 고유한 값이기 때문에 key값으로 사용하기 적절

id가 있는경우에는 보통 id값을 key값으로 사용하게 됨.


3. key로 index를 사용하는 경우 : map 함수에서 두번째 파라미터로 제공해주는 index 값을 key값으로 사용하는 것 
index는 배열 내에서 현재 item의 index를 의미, index값도 고유한 값 => key값으로 사용 가능

배열에서 item 순서가 바뀔 수 있는 경우 => key값으로 index를 사용하는 것 권장하지 않음

(성능의 부정적인 영향을 끼칠 수 있고, 컴퍼넌트의 state와 관련하여 문제를 일으킬 수 있기 때문)
따라서 index를 key값으로 사용하는 것은 item들의 고유한 id가 없을경우에만 사용하는것이 적절
참고로 React에서는 key를 명시적으로 넣어주지 않으면 기본적으로 index값을 key값으로 사용

즉, map() 함수 안에 있는 Elements는 꼭 key가 필요하다.