React useEffect vs useLayoutEffect
✨React에서의 render와 paint
- render : DOM을 구성하기 위해 각 엘리먼트의 속성을 계산하는 과정
- paint: 실제 스크린에 Layout을 표시하고 업데이트하는 과정
✨useEffect
📘useEffect 실행 단계
component → Render → Paint → useEffect
useEffect는 컴포넌트들이 render와 paint된 후에 실행된다. 비동기적으로 DOM이 그려지고난 후에 상태 값에 따라 다시 렌더링된다.
따라서 useEffect 내부에 DOM에 영향을 주는 코드가 있다면 화면이 깜빡이게 된다.
📘문법
1
2
3
4
useEffect(() => {
// do side effects
return () => /* cleanup */
}, [dependancy array]);
- 의존성 배열을 통해 어떤 상태 또는 props가 변경될 때 실행시킬지를 정함
📘useEffect 예1 - 빈 의존성 배열
현재 시간 구하기 (시간, 분, 초)
- 1초에 한번씩
setTime()
실행하여 현재 시각을 가져오는 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Time() {
const [time, setTime] = useState(getTime());
const getTime = () => {
const now = new Date();
return `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()} `;
};
useEffect(() => {
const timer = setInterval(() => {
setTime(getTime());
}, 1000);
return () => clearInterval(timer);
}, []);
return <h2>{time}</h2>;
}
useEffect
의 의존성 배열이 비어있기 때문에 처음에 마운트 될 때만 실행- 컴포넌트가 언마운트될 때
return () => clearInterval(timer);
코드가 실행되어 타이머를 정지시킴
See the Pen Untitled by 혬 (@jexbagvl-the-reactor) on CodePen.
📘useEffect 예2 - 의존성 배열 활용
시작버튼을 누르면 타이머가 실행되고, 멈춤 버튼을 누르면 타이머가 종료되는 타이머
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Timer() {
const [running, setRunning] = useState(false);
const [timer, setTimer] = useState(0);
useEffect(() => {
let timeId;
if (running) {
timeId = setInterval(() => {
setTimer((prevTime) => prevTime + 1);
}, 1000);
}
return () => clearInterval(timeId);
}, [running]);
return (
<>
<h2>{timer}초</h2>
<button onClick={() => setRunning(true)}>시작</button>
<button onClick={() => setRunning(false)}>멈춤</button>
</>
);
}
useEffect
의 의존성 배열에 running이 들어있기 때문에 처음 마운트 될 때와 running의 상태가 변경될 때마다 실행됨- running이 true일 때에는
setInterval()
로직이 실행 - running이 false일 때와 컴포넌트가 언마운트 될 때
return () => clearInterval(timeId);
코드가 실행되어 타이머가 종료됨
See the Pen Untitled by 혬 (@jexbagvl-the-reactor) on CodePen.
✨useLayoutEffect
📘useLayoutEffect 실행 단계
component → Render → useLayoutEffect → Paint
useEffect와 동일하지만, 실행시점이 다르다. useLayoutEffect는 렌더링된 후 paint 전에 동기적으로 실행된다.
즉, 브라우저가 화면을 다시 그리기 전에 실행되기때문에 DOM을 조작하는 코드가 존재하더라도 사용자는 깜빡임을 보지 않는다.
애니메이션 구현같이 반응이 바로 나타나야하는 경우에 사용하는 것이 좋다.
📘문법
1
2
3
4
useLayoutEffect(() => {
// do side effects
return () => /* cleanup */
}, [dependancy array]);
📘useLayoutEffect 예
윈도우 리사이즈 감지
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import React, { useState, useLayoutEffect } from "react";
function WindowWidth() {
// window.innerWidth을 초기값으로 세팅
const [width, setWidth] = useState(window.innerWidth);
useLayoutEffect(() => {
const handleResize = () => {
setWidth(window.innerWidth);
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
return (
<div>
<h2>Window Width: {width}px</h2>
</div>
);
}
export default WindowWidth;
useLayoutEffect
의 의존성 배열이 비어있기 때문에 처음에 마운트 될 때만 실행- 컴포넌트가 언마운트될 때
return () => window.removeEventListener("resize", handleResize)
가 실행되어 이벤트 리스너를 정리
See the Pen Untitled by 혬 (@jexbagvl-the-reactor) on CodePen.
결론
useEffect
와 useLayoutEffect
는 비슷하다. “언제 실행되는지”만 다르다.
useEffect
는 render와 paint가 모두 실행되고 난 뒤에 실행useLayoutEffect
는 paint가 실행되기 전에 실행
useLayoutEffect
를 사용하면 성능이 저하될 수 있기때문에 useEffect
를 사용해보고, 버그가 발생할 경우 useLayoutEffect
를 사용하는 것이 좋다!
참고 사이트
This post is licensed under CC BY 4.0 by the author.