일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 리액트
- 솔리디티
- 쿠버네티스
- 가상화
- 컴퓨터공학
- 프론트엔드
- HTML
- 자바스크립트
- 이더리움
- 웹
- kubernetes
- AWS
- node.js
- 클라우드
- 백준
- docker
- 타입스크립트
- TypeScript
- CSS
- 이슈
- 알고리즘
- k8s
- next.js
- BFS
- es6
- 백엔드
- 블록체인
- JavaScript
- react
- 파이썬
Archives
- Today
- Total
즐겁게, 코드
이벤트 핸들러, 제대로 제거하고 계셨나요? 본문
자바스크립트 단에서 화면 사이즈를 기반으로 모바일 여부를 검사하는 useIsMobile
훅을 제작하고 있었습니다.
import { useEffect, useState } from "react";
const useIsMobile = () => {
const [isMobile, setIsMobile] = useState(false);
const [screenWidth, setScreenWidth] = useState(0);
const handleScreenResize = () => {
setScreenWidth(window.innerWidth);
screenWidth > 768 ? setIsMobile(false) : setIsMobile(true);
};
useEffect(() => {
handleScreenResize();
window.addEventListener("resize", handleScreenResize);
}, [screenWidth]);
return isMobile;
};
export default useIsMobile;
어떤가요? 얼핏 보기엔 꽤나 그럴싸해 보이지 않나요? (물론 제게만 그럴수도 있습니다 하하하! 😆)
하지만 이 코드에는 문제가 하나 있었습니다.
콘솔을 찍어보니 화면을 조정할 때마다 true와 false 값이 번갈아가며 출력되고 있었는데요, 안에서 대체 무슨 일이 일어난 걸까요?
import { useEffect, useState } from "react";
const useIsMobile = () => {
const [isMobile, setIsMobile] = useState(false);
const [screenWidth, setScreenWidth] = useState(0);
const handleScreenResize = () => {
setScreenWidth(window.innerWidth);
screenWidth > 768 ? setIsMobile(false) : setIsMobile(true);
console.log(screenWidth); // 추가한 부분
};
useEffect(() => {
handleScreenResize();
window.addEventListener("resize", handleScreenResize);
}, [screenWidth]);
return isMobile;
};
export default useIsMobile;
이후 추가적인 확인을 위해 화면 사이즈를 변경할 때마다 그 값을 콘솔에 출력해보니, 이전까지 출력되었던 모든 너비값들이 모두 저장되어 있었고, 이 모든 값들이 다시 평가되는 과정에서 true / false 값이 섞여 출력되는 것임을 알 수 있었습니다. 🙂
그럼 이 코드의 어떤 부분에 문제가 있었던 걸까요?
맞습니다! 바로 useEffect
내부에서 이벤트 핸들러 함수를 등록할 때 이를 초기화해주지 않은 것이 문제였는데요, 지금까지의 함수 동작 과정을 한번 살펴보겠습니다.
const BaseLayout = ({ children }: BaseLayoutProps) => {
// 1. useIsMobile 훅이 호출됩니다.
const isMobile = useIsMobile();
...
}
import { useEffect, useState } from "react";
const useIsMobile = () => {
const [isMobile, setIsMobile] = useState(false);
const [screenWidth, setScreenWidth] = useState(0);
// 3. 이벤트 핸들러 내부에서 상태 업데이트가 일어나, 컴포넌트가 재렌더링됩니다.
// 즉, 핸들러가 초기화되지 않은 상태에서 1번 단계로 돌아가 위 과정을 반복합니다.
const handleScreenResize = () => {
setScreenWidth(window.innerWidth);
screenWidth > 768 ? setIsMobile(false) : setIsMobile(true);
};
// 2. 이펙트 내부에서 이벤트 핸들러가 등록됩니다.
useEffect(() => {
handleScreenResize();
window.addEventListener("resize", handleScreenResize);
}, [screenWidth]);
return isMobile;
};
export default useIsMobile;
따라서 리사이징을 감지해 상태를 업데이트한 후, 해당 이벤트 핸들러를 무효화해야 원하는 결과를 얻을 수 있게 됩니다.
import { useEffect, useState } from "react";
const useIsMobile = () => {
const [isMobile, setIsMobile] = useState(false);
const [screenWidth, setScreenWidth] = useState(0);
const handleScreenResize = () => {
setScreenWidth(window.innerWidth);
screenWidth > 768 ? setIsMobile(false) : setIsMobile(true);
// 리사이징이 수행된 다음, 이벤트 핸들러를 제거합니다.
window.removeEventListener("resize", handleScreenResize);
};
useEffect(() => {
handleScreenResize();
window.addEventListener("resize", handleScreenResize);
}, [screenWidth]);
return isMobile;
};
export default useIsMobile;
여러분들도 이벤트 핸들러를 등록하는 로직을 작성할 때, 핸들러가 필요 없어질 때는 꼭 핸들러를 제거해야 함을 잊지 말아주세요!
+ 혹시 동작 과정에 잘못된 내용이나 추가할 내용이 있다면, 댓글로 피드백을 남겨주시면 감사히 배우겠습니다! 😆
반응형
'🎨 프론트엔드 > React.js' 카테고리의 다른 글
React 18의 "Property 'children' does not exist..." 이슈 (0) | 2022.06.26 |
---|---|
미리 만나보는 automatic batching (0) | 2021.12.27 |
ReactNode, ReactChild, ReactElement 타입 비교 (0) | 2021.10.16 |
야, 너도 상태관리 할 수 있어 2편 : 리코일 사용하기 (0) | 2021.08.25 |
야, 너도 상태관리 할 수 있어 1편 : 리코일이란? (1) | 2021.08.24 |
Comments
소소한 팁 : 광고를 눌러주시면, 제가 뮤지컬을 마음껏 보러다닐 수 있어요!
와!! 바로 눌러야겠네요! 😆