react에서 사용하는 useEffect와 useLayoutEffect의 차이점이 뭘까.
일단 둘다 컴포넌트가 mount될 때 무언가 작업하기 위해서 사용하는 hook이다.
그럼 차이점은? 바로 실행되는 타이밍이다. 브라우저의 동작으로 알아보자.
- 브라우저에서 도메인을 쳐서 html을 요청한다.
- 요청받은 서버는 도메인의 html을 내려준다.
- 브라우저는 전달 받은 html을 한 줄 씩 읽어서 DOM을 생성하기 시작한다.
- 이때 CSS를 만나면 CSSOM을 생성하고, link나 script태그를 만나면 DOM생성을 잠시 멈추고 해당 리소스를 요청한다.
- DOM과 CSSOM을 완성하면, 이를 하나로 합쳐서 Render tree로 만든다. Render tree에는 DOM element중에서도 실제 브라우저에 그려지는 요소만 존재한다.
- Render tree를 기반으로 각 DOM 요소의 위치를 잡는 layout 과정에 들어간다. layout과정이 끝나면, 실제 브라우저에 요소를 그리는 paint과정을 통해 사용자에게 보여진다.
자 이렇게 우리가 알고 있는 기본적인 브라우저가 html을 그리는 동작 과정이다. 여기서 React라면 virtual DOM을 만들고, Render함수를 호출하여 virtual DOM과 DOM을 비교하는 과정을 통해 실제 화면이 그려진다.
이때 React의 Render함수의 동작은 virtual DOM의 업데이트(render phase)와 실제 DOM에 변경점을 반영하는 과정(commit phase)으로 구분지어 볼 수 있다.
useEffect의 경우, Render함수 호출 이후 virtual DOM의 업데이트와 실제 DOM에 변경을 반영한 후 비동기적으로 동작한다. 즉 useEffect안에서 상태를 변경하는 코드가 있는 경우에
- state의 변경으로 Render함수 호출됨.
- Render함수가 virtual DOM을 업데이트하고 실제 DOM에 반영함(화면 변경을 사용자가 봄)
- useEffect가 실행되어 callback함수 내부의 코드 실행, 다시 상태 업데이트
- Render함수 실행되어 또 virtual DOM을 업데이트하고 실제 DOM에 반영함(화면이 변경되며 깜빡이는 것 처럼 보임)
그렇다면 useLayoutEffect의 경우, Render함수 호출 이후 virtualDOM에 변경점을 업데이트하고 나서 동기적으로 실행된다고 한다. 이를 순서대로 보면
- state의 변경으로 Render함수 호출됨
- Render함수 호출로 virtual DOM을 업데이트하고 useLayoutEffect의 효과 발동(화면 변경 없음)
- useLayoutEffect에서 상태를 업데이트
- Render함수 실행되어 virtual DOM을 업데이트하고 DOM 업데이트(화면 변경)
간단하게 말해서 hook이 실행되는 타이밍이 commit phase 이전인지, 이후인지 차이가 있으며, useEffect는 비동기, useLayoutEffect는 동기로 동작한다.