일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 27 | 28 | 29 | 30 |
- useEffect return
- Vue3 Router
- frontend roadmap study
- 모던 javascript Deep Dive
- 프로그래머스 K_Digital Training
- KDT 프로그래머스 데브코스 프론트엔드
- 머쓱이
- 프로그래머스 데브코스
- KDT 프로그래머스
- K_Digital Training
- 백준 node.js
- react 프로젝트 리팩토링
- useRef 지역 변수
- 프로그래머스 데브코스 프론트엔드 TIL
- 우테캠 회고록
- 모던 자바스크립트 Deep Dive TIL
- 백준 js
- 투포인터알고리즘 js
- 인프런 자바스크립트 알고리즘 문제풀이
- 프로그래머스 K_Digital Training 프론트엔드
- 모던 자바스크립트 딥다이브
- Frontend Roadmap
- Vue3
- TypeScript 문법 소개
- 리팩토링 회고
- 모던 자바스크립트 Deep Dive
- 프로그래머스 데브코스 프론트엔드
- react customHook 예시
- 개발자 특강
- 모던 자바스크립트 TIL
- Today
- Total
프론트엔드 개발자의 기록 공간
requestAnimationFrame 사용법 본문
requestAnimationFrame이 무엇인지 알아보기 전에 다음과 같은 이슈를 만난적이 있나요?
(requestAnimationFrame 개념을 바로 습득하고 활용 사례를 보고 싶다면, requestAnimationFrame 타이틀로 바로 이동하셔도 무방합니다.)
useEffect 비동기로 인한 이슈
개요 : 사용자에게 화면을 제공한 후 어떠한 로직을 처리하고 싶어서 useEffect에 해당 로직을 작성했지만,
화면 표시전에 로직이 실행되어 (컴포넌트 렌더링과 화면에 노출 시점의 간극으로 인해) 문제가 되었던 적이 있나요?
제가 겪었던 이슈를 말씀드리겠습니다.
제가 원했던 경우는 사용자에게 화면을 제공한 후 searchParams값이 있으면 alert 띄우기라는 단순한 조건이었습니다.
이를 위해 다음과 같은 로직을 작성했습니다.
const [searchParams] = useSearchParams()
const isAlert = searchParams.has("keyword")
useEffect(() => {
if (isAlert) {
alert("requestAnimationFrame")
}
}, [isAlert])
이미지 순서를 보면 다음과 같습니다. 컴포넌트 마운트 -> useEffect 실행 -> alert 실행 -> dom paint과정으로 실제 화면에 렌더링
브라우저에서는 alert 함수 실행시 자바스크립트를 blocking합니다.
즉 위와 같이 되는 이유는 useEffect는 브라우저가 DOM 업데이트를 완료한 후 실행되지만, 이는 비동기적으로 실행되기 때문에 정확한 보장이 되지 않기 때문입니다. (참고 문서)
그럼 해결 방법을 알아보겠습니다.
흔히 자주들 사용하는 방법은 setTimeout과 같이 비동기 함수에 등록해서 나중에 실행되도록 억지로(?) 맞추는 방법입니다.
useEffect(() => {
if (isAlert) {
setTimeout(() => {
alert("requestAnimationFrame")
}, 1)
}
}, [isAlert])
하지만 setTimeout도 1ms로 설정하면 동일합니다. 이를 맞추기 위해 억지로 시간을 100ms로 늘려보겠습니다.
억지로 setTimeout 시간을 늘려서 맞추니깐 이번에는 원하는대로 동작합니다.
과연 이게 올바르게 해결한 것일까요? 보다 똑똑하고 올바르게 해결하는 방법을 소개해드리겠습니다.
window.requestAnimationFrame
mdn : window.requestAnimationFrame() 메서드는 브라우저에게 수행하기를 원하는 애니메이션을 알리고 다음 리페인트 바로 전에 브라우저가 애니메이션을 업데이트할 지정된 함수를 호출하도록 요청합니다. 이 메서드는 리페인트 이전에 호출할 인수로 콜백을 받습니다
즉, 브라우저가 웹 페이지의 콘텐츠를 화면에 표시하기 전에 실행하는 함수로 이해하면 됩니다.
requestAnimationFrame 장점
백그라운드 동작 중지
requestAnimationFrame는 페이지가 비활성화 된 상태이면 페이지 화면 그리기 작업도 브라우저에 의해 일시 중지됨으로 CPU 리소스나 배터리 수명을 낭비하지 않게 됩니다.
디스플레이 주사율에 맞게 호출 횟수
requestAnimationFrame는 모니터 주사율을 그대로 따르게 되어 최적화 되어 있습니다. 이러한 특성 때문에 rAF는 스크롤 이벤트 최적화 기법으로도 쓰이기도 한다.
requestAnimationFrame 사용법은 콜백 함수 내부에서 재귀 호출 하는 식으로 구성하면 됩니다. 브라우저는 애니메이션 프레임을 출력할 때마다 requestAnimationFrame 에 등록된 콜백 함수들을 비동기로 호출하여, 애니메이션을 부드럽게 출력해줍니다.
왜 재귀로 호출해야하는지 의문이 생길수도 있습니다. (제가 그랬습니다....)
단일 호출의 경우
requestAnimationFrame(() => {
alert("Hello, Vite + React!")
})
이 코드에서는 requestAnimationFrame에 전달된 콜백 함수가 브라우저의 다음 애니메이션 프레임이 시작되기 전에 실행됩니다. 이는 일반적으로 현재 프레임이 끝난 후, 다음 프레임이 시작되기 전 시점입니다. 즉, 브라우저가 현재 작업을 완료하고, 렌더링을 준비하기 전에 콜백이 호출됩니다.
재귀적으로 두 번 호출하는 경우
requestAnimationFrame(() => {
requestAnimationFrame(() => {
alert("Hello, Vite + React!")
})
})
이 코드에서는 첫 번째 requestAnimationFrame 콜백이 브라우저의 다음 애니메이션 프레임이 시작되기 전에 실행됩니다. 그러나 이 콜백 내에서 또 다른 requestAnimationFrame이 호출되므로, 두 번째 콜백은 그 다음 애니메이션 프레임이 시작되기 전에 실행됩니다. 따라서, 두 번째 콜백은 첫 번째 콜백이 실행된 프레임 다음의 프레임에서 실행됩니다.
useEffect(() => {
if (isAlert) {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
alert("Hello, Vite + React!")
})
})
}
}, [isAlert])
이제 결과를 보면 하위의 Vite+React 글자가 보이고 난 후 alert를 띄우는 것을 볼 수 있습니다!!! 🥳🥳🥳🥳🥳🥳🥳🥳
위 gif를 자세히 보면 첫번째 새로고침에는 vite, react이미지 로고가 보이고 나서 alert를 띄우지만,
두번째 새로고침을 보면 이미지 노출되기전에 alert를 실행시키는 상황도 생깁니다. 이 경우는 다양하게 해결할 수 있지만,
ref를 활용해서 이미지가 dom에 있는 경우를 판단해서 alert를 실행시키면 됩니다.
requestAnimationFrame의 개념과 이론을 더 자세히 알고 싶으면 아래 레퍼런스를 참고해주시면 될 것 같습니다.
프레임과 task와 같은 중요한 개념을 상세히 다루고 있습니다.
출처: https://inpa.tistory.com/entry/🌐-requestAnimationFrame-가이드 [Inpa Dev 👨💻:티스토리]
'개발지식' 카테고리의 다른 글
[FE_Roadmap] Web Components (2) | 2024.06.02 |
---|---|
[FE_Roadmap] writing css & testing your apps (0) | 2024.03.02 |
[FE_Roadmap] Pick a Framework (1) | 2024.02.18 |
[FE_Roadmap] Module Bundlers (0) | 2024.02.13 |
[FE_Roadmap] CSS Architecture&CSS Preprocessors (1) | 2023.12.17 |