diff --git a/components/DanmakuList.tsx b/components/DanmakuList.tsx index f92436c..df55433 100644 --- a/components/DanmakuList.tsx +++ b/components/DanmakuList.tsx @@ -47,7 +47,7 @@ export default function DanmakuList({ danmakus, currentTime, visible, onToggle } String(i)} + keyExtractor={(item, i) => `${item.time}_${item.text}_${i}`} style={styles.list} renderItem={({ item }) => ( >(new Set()); const prevTimeRef = useRef(currentTime); const idCounter = useRef(0); + const mountedRef = useRef(true); + useEffect(() => { + return () => { mountedRef.current = false; }; + }, []); const pickLane = useCallback((): number | null => { const now = Date.now(); @@ -37,6 +41,12 @@ export default function DanmakuOverlay({ danmakus, currentTime, screenWidth, scr return null; }, []); + useEffect(() => { + activated.current.clear(); + laneAvailAt.current.fill(0); + setActiveDanmakus([]); + }, [danmakus]); + useEffect(() => { if (!visible) return; @@ -63,9 +73,9 @@ export default function DanmakuOverlay({ danmakus, currentTime, screenWidth, scr const newItems: ActiveDanmaku[] = []; + if (activated.current.size > 200) activated.current.clear(); // prevent memory leak for (const item of candidates) { const key = `${item.time}_${item.text}`; - if (activated.current.size > 200) activated.current.clear(); // prevent memory leak activated.current.add(key); if (item.mode === 1) { @@ -94,7 +104,7 @@ export default function DanmakuOverlay({ danmakus, currentTime, screenWidth, scr duration, useNativeDriver: true, }).start(() => { - setActiveDanmakus(prev => prev.filter(d => d.id !== id)); + if (mountedRef.current) setActiveDanmakus(prev => prev.filter(d => d.id !== id)); }); } else { // Fixed danmaku (mode 4 = bottom, mode 5 = top) @@ -106,7 +116,7 @@ export default function DanmakuOverlay({ danmakus, currentTime, screenWidth, scr Animated.delay(2000), Animated.timing(opacity, { toValue: 0, duration: 500, useNativeDriver: true }), ]).start(() => { - setActiveDanmakus(prev => prev.filter(d => d.id !== id)); + if (mountedRef.current) setActiveDanmakus(prev => prev.filter(d => d.id !== id)); }); } } diff --git a/components/NativeVideoPlayer.tsx b/components/NativeVideoPlayer.tsx index 9ad15d6..16ea38e 100644 --- a/components/NativeVideoPlayer.tsx +++ b/components/NativeVideoPlayer.tsx @@ -9,7 +9,7 @@ import { Ionicons } from '@expo/vector-icons'; import type { PlayUrlResponse, VideoShotData, DanmakuItem } from '../services/types'; import { buildDashMpdUri } from '../utils/dash'; import { getHeatmap, getVideoShot } from '../services/bilibili'; -import { DanmakuOverlay } from './DanmakuOverlay'; +import DanmakuOverlay from './DanmakuOverlay'; const BAR_H = 3; const BALL = 12;