Virtual Dom

devAnderson·2022년 1월 12일
0

TIL

목록 보기
24/103

why virtual dom

일반적으로 브라우저가 웹페이지를 화면에 보일 때에는 크게 2가지의 경우의 수가 존재한다.
1. html 문서를 파싱하여 DOM 트리를 만든다
2. 그 후, DOM의 요소가 변경될 때마다 Reflow, Repaint를 진행한다.

<브라우저의 페이지 랜더링 모식도>



이게 단순히 한두가지의 컴포넌트가 변경되는 것이 아닌 여러개의 자식들이 동시에 변경되야 한다면 몹시 퍼포먼스가 느려진다
virtual dom은 이 느린 퍼포먼스를 해결하기 위해 만들어진 React의 방식이다

react life cycle

  1. 생명주기는 마운트, 업데이트, 언마운트로 이루어진다
  2. 첫 마운트 당시에는 클래스 컴포넌트는 constructor, 함수 컴포넌트는 useState을 통해 객체 내 상태를 설정한다.
  3. getDerivedStateFromProps를 통해 기존의 state과, 현재의 state을 비교해본다. 변경이 있다면 업데이트 대상이다

    만약 getDerivedStateFromProps의 값이 존재한다면, shouldComponentUpdate로 true를 리턴한다. (클래스 컴포넌트)
    React.memo(component, (nextState,prevState)=> nextState.value === prevState.value)로 이루어짐 (함수 컴포넌트)

class Example extends React.Component {
  static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.value !== prevState.value) {
      return { value: nextProps.value }
    }
    return null
  }
}
  1. render 메서드를 통해 virtual dom을 형성한다
  2. virtual dom이 실제 dom에 적용되기 전 getSnapshotBeforeUpdate를 호출하여 업데이트 전 실행해야 할 작업을 진행한다
  3. componentDidMount를 통해 dom이 업데이트 된 이후 작업할 내용을 호출한다. (함수형은 useEffect의 빈배열 디펜던시)
  4. componentDidUpdate를 통해 새로운 업데이트에 대한 작업내용을 호출한다. (함수형은 useEffect의 비워진 두번째 인자, 혹은 요소가 있는 배열)

    componentDidUpdate는 shouldComponentUpdate의 리턴값이 true일때만 호출된다.

  5. componentWillUnmount를 통해 Dom에서 해당 내용이 언마운트 됬을 때 호출한다 (함수형은 useEffect의 콜백함수의 리턴되는 함수)

virtual DOM의 내부

render을 호출하여 virtual DOM이 이루어지는건 알겠는데, 그 세부적인 사항에 대해서 조금 더 들어가자면

예를들어, 초기 랜더링을 통해 실제 DOM에 반영되는 요소들이 위와 같다면 virtual DOM 의 상태는 아래와 같다

사실 실제 DOM과 크게 다르지 않고, 어트리뷰트 노드가 props라고 하는 jsx객체 안에 전부 다 들어가있는 형태로 되어있는 차이정도가 있다.
만약 여기서 add버튼을 실제로 누르게 된다면

//Calculator.js
<button id="add" onClick={ () => {
      IntegerA = parseInt(ReactDOM.findDOMNode(this.refs.input1).value)
      IntegerB = parseInt(ReactDOM.findDOMNode(this.refs.input2).value)
      IntegerC = IntegerA+IntegerB
      this.setState({output:IntegerC})
       }
     }>Add</button>

DOM의 event객체는 react의 커스텀 이벤트 객체의 래퍼객체이므로, 리엑트 객체는 해당 이벤트를 감지할 수 있다
이벤트가 감지가 완료되면, 리엑트는 해당 이벤트 핸들러를 호출한다. 여기서 볼 것은 이벤트 핸들러의 내부에 "this.setState" 라고 되어있는 부문으로,
여기서의 this는 화살표 함수로 인해 상위 스코프의 This, 즉 Calulator 컴포넌트가 가리키는 this가 된다.

따라서, 이 this의 상태업데이트 정보에 따라 리엑트는 자신들의 내부에 있는 "Dirty Component 리스트에 해당 컴포넌트를 삽입한다

후에 이 Dirty component리스트를 순회하며 배치업데이트를 실행한다(배치업데이트는 더티 컴포넌트 리스트를 해제하면서 차례대로 업데이트를 실행한다)

그 후 도출되는 pending state(변경된 상태값) 들을 queue로 집어넣는다

그 큐들을 보면서 shouldComponentUpdate의 호출이 발생했을 시 새로운 상태로 랜더링을 진행한 후, virtual dom에 있는 내용을 토대로 실제 dom의 내용을 변경시킨다.

이때, 랜더링을 위해 참조하는 값들이 type과 key라고 한다.
실제로는 이것보다 더 많고, 복잡한 과정이 엄청나게 많지만 현재 내가 다 이해하기는 무리일 것 같으므로 이해가 되는 부분들만 간략하게 정리하였다

Referrence

how to virtual dom update real dom
deep understand of virtual dom

profile
자라나라 프론트엔드 개발새싹!

0개의 댓글