[Perf] useVideoCleanup: Remove event listeners

This commit is contained in:
Alexander Zinchuk 2024-09-19 20:43:40 +02:00
parent 9ad5cf4909
commit af9d8695f4
4 changed files with 22 additions and 9 deletions

View File

@ -181,7 +181,8 @@ const VideoPlayer: FC<OwnProps> = ({
}
});
useVideoCleanup(videoRef, []);
useVideoCleanup(videoRef, bufferingHandlers);
const [, setCurrentTime] = useCurrentTimeSignal();
const [, setIsVideoWaiting] = useVideoWaitingSignal();

View File

@ -36,7 +36,6 @@ function OptimizedVideo({
}
const { handlePlaying: handlePlayingForAutoPause } = useVideoAutoPause(ref, canPlay, isPriority);
useVideoCleanup(ref, []);
const isReadyRef = useRef(false);
const handleReady = useLastCallback(() => {
@ -77,6 +76,8 @@ function OptimizedVideo({
return mergedHandlers;
}, [otherBufferingHandlers, restProps]);
useVideoCleanup(ref, mergedOtherBufferingHandlers);
return (
// eslint-disable-next-line react/jsx-props-no-spreading
<video ref={ref} autoPlay {...restProps} {...mergedOtherBufferingHandlers} onPlaying={handlePlaying}>

View File

@ -1,20 +1,31 @@
import type { RefObject } from 'react';
import { onFullyIdle, useEffect } from '../lib/teact/teact';
import { resolveEventType } from '../lib/teact/dom-events';
import { onFullyIdle, useLayoutEffect } from '../lib/teact/teact';
import unloadVideo from '../util/browser/unloadVideo';
import { useStateRef } from './useStateRef';
// Fix for memory leak when unmounting video element
export default function useVideoCleanup(videoRef: RefObject<HTMLVideoElement>, dependencies: any[]) {
useEffect(() => {
// Fix memory leak when unmounting video element
export default function useVideoCleanup(videoRef: RefObject<HTMLVideoElement>, handlers?: Record<string, AnyFunction>) {
const handlersRef = useStateRef(handlers);
useLayoutEffect(() => {
const videoEl = videoRef.current;
if (!videoEl) return undefined;
return () => {
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
const handlers2 = handlersRef.current;
if (handlers2) {
Object.entries(handlers2).forEach(([key, value]) => {
videoEl.removeEventListener(resolveEventType(key, videoEl), value, false);
});
}
// It may be slow (specifically on iOS), so we postpone it after unmounting
onFullyIdle(() => {
unloadVideo(videoEl);
});
};
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
}, dependencies);
}, [handlersRef, videoRef]);
}

View File

@ -27,7 +27,7 @@ export function removeEventListener(element: Element, propName: string, handler:
}
}
function resolveEventType(propName: string, element: Element) {
export function resolveEventType(propName: string, element: Element) {
const eventType = propName
.replace(/^on/, '')
.replace(/Capture$/, '').toLowerCase();