refactor: 메모리 누수 정리 및 타이머 관리 개선, 이벤트 리스너 제거 함수 추가
This commit is contained in:
@@ -19,6 +19,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
})
|
||||
|
||||
const videoRef = ref<HTMLVideoElement | null>(null)
|
||||
let pauseTimeoutId: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
// autoplay prop 변경 시 재생/정지 제어
|
||||
watch(
|
||||
@@ -26,19 +27,36 @@ watch(
|
||||
shouldPlay => {
|
||||
if (!videoRef.value) return
|
||||
|
||||
// 이전 타이머 정리
|
||||
if (pauseTimeoutId) {
|
||||
clearTimeout(pauseTimeoutId)
|
||||
pauseTimeoutId = null
|
||||
}
|
||||
|
||||
if (shouldPlay) {
|
||||
videoRef.value.play().catch(err => {
|
||||
console.warn('Video play failed:', err)
|
||||
})
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
videoRef.value.pause()
|
||||
videoRef.value.currentTime = 0
|
||||
pauseTimeoutId = setTimeout(() => {
|
||||
if (videoRef.value) {
|
||||
videoRef.value.pause()
|
||||
videoRef.value.currentTime = 0
|
||||
}
|
||||
pauseTimeoutId = null
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
// 타이머 정리
|
||||
if (pauseTimeoutId) {
|
||||
clearTimeout(pauseTimeoutId)
|
||||
pauseTimeoutId = null
|
||||
}
|
||||
})
|
||||
|
||||
// src 변경 시 비디오 다시 로드
|
||||
watch(
|
||||
() => props.src,
|
||||
|
||||
@@ -26,6 +26,7 @@ const { addArrowClickListeners } = useSplideArrow()
|
||||
|
||||
let mainInst: SplideType | null = null
|
||||
let thumbsInst: SplideType | null = null
|
||||
let removeArrowListeners: (() => void) | null = null
|
||||
|
||||
defineExpose({
|
||||
mainInst: computed(() => mainInst),
|
||||
@@ -111,7 +112,7 @@ onMounted(() => {
|
||||
mainInst.sync(thumbsInst)
|
||||
// 썸네일 슬라이드의 화살표 버튼에 이벤트 리스너 추가
|
||||
nextTick(() => {
|
||||
addArrowClickListeners(thumbsInst, (direction, targetIndex) => {
|
||||
removeArrowListeners = addArrowClickListeners(thumbsInst, (direction, targetIndex) => {
|
||||
emit('arrowClick', direction, targetIndex)
|
||||
})
|
||||
})
|
||||
@@ -119,8 +120,17 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
// 이벤트 리스너 제거
|
||||
if (removeArrowListeners) {
|
||||
removeArrowListeners()
|
||||
removeArrowListeners = null
|
||||
}
|
||||
|
||||
// Splide 인스턴스 정리
|
||||
mainInst?.destroy?.()
|
||||
thumbsInst?.destroy?.()
|
||||
mainInst = null
|
||||
thumbsInst = null
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ export const useCheckGameStart = () => {
|
||||
const isShowCheckLauncher = ref(false) // 런처 실행 로딩 표시
|
||||
const isShowDownloadLauncher = ref(false) // 런처 다운로드 표시
|
||||
const customerServiceUrl = `${stoveCs}/${gameData.value?.game_id}`
|
||||
let launcherTimeoutId: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
// 에러 처리
|
||||
const errorHandler = (errorCode: number) => {
|
||||
@@ -64,13 +65,20 @@ export const useCheckGameStart = () => {
|
||||
// 런처 실행 로딩 시작 UI 처리
|
||||
const startLoadingForLauncher = () => {
|
||||
if (import.meta.client) {
|
||||
// 이전 타이머 정리
|
||||
if (launcherTimeoutId) {
|
||||
clearTimeout(launcherTimeoutId)
|
||||
launcherTimeoutId = null
|
||||
}
|
||||
|
||||
isShowCheckLauncher.value = true
|
||||
isShowDownloadLauncher.value = false
|
||||
|
||||
setTimeout(() => {
|
||||
launcherTimeoutId = setTimeout(() => {
|
||||
if (isShowCheckLauncher.value) {
|
||||
isShowDownloadLauncher.value = true
|
||||
}
|
||||
launcherTimeoutId = null
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
@@ -78,6 +86,12 @@ export const useCheckGameStart = () => {
|
||||
// 런처 실행 로딩 종료 UI 처리
|
||||
const stopLoadingForLauncher = () => {
|
||||
if (import.meta.client) {
|
||||
// 타이머 정리
|
||||
if (launcherTimeoutId) {
|
||||
clearTimeout(launcherTimeoutId)
|
||||
launcherTimeoutId = null
|
||||
}
|
||||
|
||||
isShowCheckLauncher.value = false
|
||||
isShowDownloadLauncher.value = false
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ export const useSplideArrow = () => {
|
||||
* 화살표 버튼에 클릭 이벤트 리스너를 추가하는 함수
|
||||
* @param splide - Splide 인스턴스
|
||||
* @param onArrowClick - 화살표 클릭 시 실행될 콜백 함수
|
||||
* @returns 이벤트 리스너 제거 함수
|
||||
*/
|
||||
const addArrowClickListeners = (
|
||||
splide: SplideType,
|
||||
@@ -51,12 +52,25 @@ export const useSplideArrow = () => {
|
||||
const prevArrow = splide.root.querySelector('.arrow-prev')
|
||||
const nextArrow = splide.root.querySelector('.arrow-next')
|
||||
|
||||
const prevHandler = () => handleArrowClick('prev', splide, onArrowClick)
|
||||
const nextHandler = () => handleArrowClick('next', splide, onArrowClick)
|
||||
|
||||
if (prevArrow) {
|
||||
prevArrow.addEventListener('click', () => handleArrowClick('prev', splide, onArrowClick))
|
||||
prevArrow.addEventListener('click', prevHandler)
|
||||
}
|
||||
|
||||
if (nextArrow) {
|
||||
nextArrow.addEventListener('click', () => handleArrowClick('next', splide, onArrowClick))
|
||||
nextArrow.addEventListener('click', nextHandler)
|
||||
}
|
||||
|
||||
// 이벤트 리스너 제거 함수 반환
|
||||
return () => {
|
||||
if (prevArrow) {
|
||||
prevArrow.removeEventListener('click', prevHandler)
|
||||
}
|
||||
if (nextArrow) {
|
||||
nextArrow.removeEventListener('click', nextHandler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,3 +80,4 @@ export const useSplideArrow = () => {
|
||||
addArrowClickListeners
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,13 @@ export const useLoadingStore = defineStore('loadingStore', () => {
|
||||
const isPAssApiLoading = ref(false)
|
||||
// 컴포넌트별 로딩 표기 - Map 대신 일반 객체 사용
|
||||
const localLoadings = ref<Record<string, { active: boolean }>>({})
|
||||
const apiLoadingTimeoutId = ref<ReturnType<typeof setTimeout> | null>(null)
|
||||
|
||||
/**
|
||||
* 로딩 상태 초기화
|
||||
*/
|
||||
const initializeStore = () => {
|
||||
|
||||
localLoadings.value = {}
|
||||
hasApiCallStarted.value = false
|
||||
isPAssApiLoading.value = false
|
||||
@@ -34,10 +36,18 @@ export const useLoadingStore = defineStore('loadingStore', () => {
|
||||
fullLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const finishApiLoading = () => {
|
||||
setTimeout(() => {
|
||||
// 이전 타이머가 있으면 정리
|
||||
if (apiLoadingTimeoutId.value) {
|
||||
clearTimeout(apiLoadingTimeoutId.value)
|
||||
apiLoadingTimeoutId.value = null
|
||||
}
|
||||
|
||||
apiLoadingTimeoutId.value = setTimeout(() => {
|
||||
hasApiCallStarted.value = false
|
||||
isPAssApiLoading.value = true
|
||||
apiLoadingTimeoutId.value = null
|
||||
}, 300)
|
||||
}
|
||||
|
||||
|
||||
@@ -118,13 +118,22 @@ export const useModalStore = defineStore('modalStore', () => {
|
||||
storeContentText: ref(''),
|
||||
}
|
||||
|
||||
const toastTimeoutId = ref<ReturnType<typeof setTimeout> | null>(null)
|
||||
|
||||
const handleOpenToast = ({ contentText, duration = 2000 }: ToastParams) => {
|
||||
// 이전 타이머가 있으면 정리
|
||||
if (toastTimeoutId.value) {
|
||||
clearTimeout(toastTimeoutId.value)
|
||||
toastTimeoutId.value = null
|
||||
}
|
||||
|
||||
toast.storeIsOpen.value = true
|
||||
toast.storeContentText.value = contentText
|
||||
|
||||
setTimeout(() => {
|
||||
toastTimeoutId.value = setTimeout(() => {
|
||||
toast.storeIsOpen.value = false
|
||||
toast.storeContentText.value = ''
|
||||
toastTimeoutId.value = null
|
||||
}, duration)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
|
||||
|
||||
const slideThumbnailRef = ref<any>(null)
|
||||
const playingSlideIndex = ref<number | null>(null)
|
||||
let stopVideoTimeoutId: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
const backgroundData = computed(() =>
|
||||
getComponentGroup(props.components, 'background')
|
||||
@@ -89,12 +90,27 @@ const handleVideoClick = (index: number) => {
|
||||
}
|
||||
|
||||
const stopVideo = () => {
|
||||
// 이전 타이머 정리
|
||||
if (stopVideoTimeoutId) {
|
||||
clearTimeout(stopVideoTimeoutId)
|
||||
stopVideoTimeoutId = null
|
||||
}
|
||||
|
||||
// 전환 시간 후 완전히 제거
|
||||
setTimeout(() => {
|
||||
stopVideoTimeoutId = setTimeout(() => {
|
||||
playingSlideIndex.value = null
|
||||
stopVideoTimeoutId = null
|
||||
}, 400)
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
// 타이머 정리
|
||||
if (stopVideoTimeoutId) {
|
||||
clearTimeout(stopVideoTimeoutId)
|
||||
stopVideoTimeoutId = null
|
||||
}
|
||||
})
|
||||
|
||||
const onArrowClick = (direction, targetIndex) => {
|
||||
const arrowGroupAry = getComponentGroupAry(props.components, 'arrow')
|
||||
const logTracking = arrowGroupAry?.[direction === 'prev' ? 0 : 1]
|
||||
|
||||
Reference in New Issue
Block a user