[251124] fix: PlayerPanel,VideoPlayer 최적화-6
🕐 커밋 시간: 2025. 11. 24. 19:23:39 📊 변경 통계: • 총 파일: 8개 • 추가: +142줄 • 삭제: -31줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/playActions.js ~ com.twin.app.shoptime/src/components/MediaItem/MediaItem.js ~ com.twin.app.shoptime/src/components/VideoPlayer/MediaTitle.js ~ com.twin.app.shoptime/src/components/VideoPlayer/TReactPlayer.jsx ~ com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js ~ com.twin.app.shoptime/src/hooks/useReviews/useReviews.js ~ com.twin.app.shoptime/src/utils/helperMethods.js ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선 • UI 컴포넌트 아키텍처 개선 • 공통 유틸리티 함수 최적화 • 중간 규모 기능 개선 • 모듈 구조 개선
This commit is contained in:
@@ -1147,3 +1147,113 @@ export const setDisplayFullscreen = () => ({
|
||||
lastUpdate: Date.now(),
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 배너 비디오를 시작합니다.
|
||||
* @param {Object} videoInfo - 비디오 정보
|
||||
* @param {string} videoInfo.bannerId - 배너 ID
|
||||
* @param {string} videoInfo.videoId - 비디오 ID
|
||||
* @param {string} videoInfo.showUrl - 비디오 URL
|
||||
* @param {boolean} videoInfo.modal - 모달 여부
|
||||
* @param {string} videoInfo.modalContainerId - 모달 컨테이너 ID
|
||||
* @param {string} videoInfo.modalClassName - 모달 클래스 이름
|
||||
*/
|
||||
export const startBannerVideo = (videoInfo) => (dispatch, getState) => {
|
||||
dlog('[startBannerVideo] ✅ START - videoInfo:', videoInfo);
|
||||
|
||||
const {
|
||||
bannerId,
|
||||
videoId,
|
||||
showUrl,
|
||||
modal = true,
|
||||
modalContainerId,
|
||||
modalClassName,
|
||||
...rest
|
||||
} = videoInfo;
|
||||
|
||||
// 비디오 식별자 생성
|
||||
const videoIdentifier = videoId || showUrl || bannerId;
|
||||
if (videoIdentifier) {
|
||||
const displayMode = modal ? DISPLAY_STATUS.VISIBLE : DISPLAY_STATUS.FULLSCREEN;
|
||||
dlog(
|
||||
'[startBannerVideo] 📌 Setting playback loading - identifier:',
|
||||
videoIdentifier,
|
||||
', displayMode:',
|
||||
displayMode
|
||||
);
|
||||
dispatch(setPlaybackLoading(videoIdentifier, displayMode));
|
||||
}
|
||||
|
||||
const panels = getState().panels.panels;
|
||||
const existingPlayerPanel = panels.find((p) => p.name === panel_names.PLAYER_PANEL);
|
||||
|
||||
// 기존 PlayerPanel이 있으면 초기화
|
||||
if (existingPlayerPanel) {
|
||||
dlog('[startBannerVideo] 🔄 Resetting existing PLAYER_PANEL before start');
|
||||
clearAllVideoTimers();
|
||||
dispatch(popPanel(panel_names.PLAYER_PANEL));
|
||||
}
|
||||
|
||||
// 새로운 PlayerPanel push
|
||||
dispatch(
|
||||
pushPanel(
|
||||
{
|
||||
name: panel_names.PLAYER_PANEL,
|
||||
panelInfo: {
|
||||
modal,
|
||||
modalContainerId,
|
||||
modalClassName,
|
||||
playerState: {
|
||||
currentBannerId: bannerId,
|
||||
},
|
||||
videoId,
|
||||
showUrl,
|
||||
bannerId,
|
||||
...rest,
|
||||
},
|
||||
},
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
dlog('[startBannerVideo] ✨ Panel action dispatched');
|
||||
};
|
||||
|
||||
/**
|
||||
* 비디오를 중지하고 화면에서 숨깁니다.
|
||||
* 패널을 닫지 않고 비디오 재생만 중지합니다.
|
||||
*/
|
||||
export const stopAndHideVideo = () => (dispatch, getState) => {
|
||||
const panels = getState().panels.panels;
|
||||
|
||||
// 모든 PlayerPanel 찾기
|
||||
const playerPanels = panels.filter((panel) => panel.name === panel_names.PLAYER_PANEL);
|
||||
|
||||
if (playerPanels.length > 0) {
|
||||
dlog('[stopAndHideVideo] Stopping all video playback and hiding');
|
||||
|
||||
// 타이머 정리
|
||||
if (startVideoFocusTimer) {
|
||||
clearTimeout(startVideoFocusTimer);
|
||||
startVideoFocusTimer = null;
|
||||
}
|
||||
|
||||
// 모든 PlayerPanel을 중지 및 숨김 상태로 업데이트
|
||||
playerPanels.forEach((playerPanel) => {
|
||||
dispatch(
|
||||
updatePanel({
|
||||
name: panel_names.PLAYER_PANEL,
|
||||
panelInfo: {
|
||||
...playerPanel.panelInfo,
|
||||
shouldStop: true,
|
||||
isPaused: true,
|
||||
isHidden: true,
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Redux 상태도 중지로 업데이트
|
||||
dispatch(setVideoStopped());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ import * as Config from "../../utils/Config";
|
||||
import * as ContentType from "../../utils/Config";
|
||||
import * as Utils from "../../utils/helperMethods";
|
||||
import { $L } from "../../utils/helperMethods";
|
||||
import SpotlightIds from "../../utils/SpotlightIds";
|
||||
import { SpotlightIds } from "../../utils/SpotlightIds";
|
||||
import css from "./MediaItem.module.less";
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,7 +10,7 @@ import { SpotlightContainerDecorator } from "@enact/spotlight/SpotlightContainer
|
||||
import ForwardRef from "@enact/ui/ForwardRef";
|
||||
|
||||
import { $L } from "../../utils/helperMethods";
|
||||
import SpotlightIds from "../../utils/SpotlightIds";
|
||||
import { SpotlightIds } from "../../utils/SpotlightIds";
|
||||
import TButton from "../TButton/TButton";
|
||||
import css from "./MediaTitle.module.less";
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ export default function TReactPlayer({
|
||||
// 🔽 [최적화] URL 변경 또는 언마운트 시 이전 비디오 정리 (메모리 누수 방지)
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
console.log('[TReactPlayer] cleanup - start', { url });
|
||||
// console.log('[TReactPlayer] cleanup - start', { url });
|
||||
const videoNode = playerRef.current?.getInternalPlayer();
|
||||
if (videoNode) {
|
||||
try {
|
||||
@@ -179,7 +179,7 @@ export default function TReactPlayer({
|
||||
console.warn('[TReactPlayer] cleanup warning:', err);
|
||||
}
|
||||
}
|
||||
console.log('[TReactPlayer] cleanup - done', { url });
|
||||
// console.log('[TReactPlayer] cleanup - done', { url });
|
||||
};
|
||||
}, [url]); // ✅ URL 변경 시에도 정리 로직 실행
|
||||
|
||||
|
||||
@@ -1020,7 +1020,7 @@ const VideoPlayerBase = class extends React.Component {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
console.log('[VideoPlayer] componentWillUnmount - start cleanup', { src: this.props?.src });
|
||||
// console.log('[VideoPlayer] componentWillUnmount - start cleanup', { src: this.props?.src });
|
||||
off('mousemove', this.activityDetected);
|
||||
if (platform.touch) {
|
||||
off('touchmove', this.activityDetected);
|
||||
@@ -1089,7 +1089,7 @@ const VideoPlayerBase = class extends React.Component {
|
||||
// 정리 중 에러는 무시하고 언마운트 진행
|
||||
// console.warn('[VideoPlayer] cleanup error', err);
|
||||
}
|
||||
console.log('[VideoPlayer] componentWillUnmount - cleanup done', { src: this.props?.src });
|
||||
// console.log('[VideoPlayer] componentWillUnmount - cleanup done', { src: this.props?.src });
|
||||
if (this.floatingLayerController) {
|
||||
this.floatingLayerController.unregister();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState, useMemo, useEffect, useCallback } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { getUserReviews, getUserReviewList, getReviewFilters, clearReviewFilter } from '../../actions/productActions';
|
||||
import { getUserReviewList, getReviewFilters, clearReviewFilter } from '../../actions/productActions';
|
||||
import fp from '../../utils/fp';
|
||||
|
||||
const DISPLAY_SIZE = 3; // 화면에 표시할 리뷰 개수
|
||||
@@ -175,11 +175,6 @@ const useReviews = (prdtId, patnrId, _deprecatedReviewVersion) => {
|
||||
// });
|
||||
|
||||
try {
|
||||
if (reviewVersion === 1) {
|
||||
// 기존 API 호출
|
||||
// console.log('[useReviews] 🔄 getUserReviews 호출 중... (v1)');
|
||||
await dispatch(getUserReviews({ prdtId, patnrId }));
|
||||
} else {
|
||||
// 신 API 호출 (v2)
|
||||
// console.log('[useReviews] 🔄 getUserReviewList 호출 중... (v2)');
|
||||
await dispatch(getUserReviewList({
|
||||
@@ -196,7 +191,6 @@ const useReviews = (prdtId, patnrId, _deprecatedReviewVersion) => {
|
||||
prdtId,
|
||||
patnrId
|
||||
}));
|
||||
}
|
||||
setHasLoadedData(true);
|
||||
} catch (error) {
|
||||
console.error('[useReviews] loadReviews 실패:', error);
|
||||
|
||||
@@ -572,3 +572,10 @@ export const getReservationErrorMessage = (error) => {
|
||||
|
||||
return $L("Failed to set reminder. Please try again.");
|
||||
};
|
||||
|
||||
export const convertNewlinesToBr = (text) => {
|
||||
if (typeof text !== 'string') {
|
||||
return text;
|
||||
}
|
||||
return text.replace(/\n/g, '<br>');
|
||||
};
|
||||
|
||||
@@ -2222,13 +2222,13 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
console.log('[PlayerPanel] unmount cleanup start');
|
||||
// console.log('[PlayerPanel] unmount cleanup start');
|
||||
cleanupPlayerOnUnmount();
|
||||
stopExternalPlayer();
|
||||
dispatch(clearShopNowInfo());
|
||||
dispatch(CLEAR_PLAYER_INFO());
|
||||
setShopNowInfo([]);
|
||||
console.log('[PlayerPanel] unmount cleanup done');
|
||||
// console.log('[PlayerPanel] unmount cleanup done');
|
||||
};
|
||||
}, [cleanupPlayerOnUnmount, stopExternalPlayer, dispatch]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user