From dcbe297d658adcd9726485b08177c4f6c684fc27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=A1vio=20Juvenal?= Date: Wed, 15 Jan 2025 22:45:36 -0300 Subject: [PATCH] Prevent unnecessary re-renders for VideoAttachment --- components/ChatMessageBubble.tsx | 90 ++++++++++++++++---------------- utils/media.ts | 18 +++++-- 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/components/ChatMessageBubble.tsx b/components/ChatMessageBubble.tsx index 5c3d7ae..301aa6b 100644 --- a/components/ChatMessageBubble.tsx +++ b/components/ChatMessageBubble.tsx @@ -3,7 +3,7 @@ import { Image } from "expo-image"; import { useVideoPlayer } from "expo-video"; import { VideoView } from "expo-video"; import { CirclePlay, FileDown, UserRound } from "lucide-react-native"; -import { useCallback, useRef, useState } from "react"; +import { memo, useCallback, useRef, useState } from "react"; import { Pressable, StyleSheet, View } from "react-native"; import { Alert } from "react-native"; @@ -14,7 +14,7 @@ import { Text } from "@/components/ui/text"; import type { ChatMessage } from "@/models/chat"; import type { AttachmentWithUrl } from "@/types/attachment"; import { formatTime } from "@/utils/datetime"; -import { mediaKey, shareFile } from "@/utils/media"; +import { isMediaExpired, mediaKey, shareFile } from "@/utils/media"; interface ChatMessageBubbleProps { message: ChatMessage; @@ -28,50 +28,53 @@ const mediaStyles = StyleSheet.create({ }, }); -function VideoAttachment({ uri }: { uri: string }) { - const player = useVideoPlayer(uri, (player) => { - player.loop = true; - player.bufferOptions = { - minBufferForPlayback: 0, - preferredForwardBufferDuration: 5, - maxBufferBytes: 0, - prioritizeTimeOverSizeThreshold: false, - waitsToMinimizeStalling: true, - }; - }); - const videoRef = useRef(null); - const [isFullscreen, setIsFullscreen] = useState(false); +const VideoAttachment = memo( + ({ uri }: { uri: string }) => { + const player = useVideoPlayer(uri, (player) => { + player.loop = true; + player.bufferOptions = { + // Reduce buffer for performance: + minBufferForPlayback: 0, + preferredForwardBufferDuration: 5, + }; + }); + const videoRef = useRef(null); + const [isFullscreen, setIsFullscreen] = useState(false); - const handlePlayPress = useCallback(() => { - if (!player) return; - player.play(); - videoRef.current?.enterFullscreen(); - setIsFullscreen(true); - }, [player]); + const handlePlayPress = useCallback(() => { + if (!player) return; + player.play(); + videoRef.current?.enterFullscreen(); + setIsFullscreen(true); + }, [player]); - const handleExitFullscreen = useCallback(() => { - setIsFullscreen(false); - }, []); + const handleExitFullscreen = useCallback(() => { + player?.pause(); + setIsFullscreen(false); + }, [player]); - return ( - - - - - - - ); -} + return ( + + + + + + + ); + }, + (oldProps: { uri: string }, newProps: { uri: string }) => + mediaKey(oldProps.uri) === mediaKey(newProps.uri) && !isMediaExpired(oldProps.uri), +); +VideoAttachment.displayName = "VideoAttachment"; function FileAttachment({ attachment }: { attachment: AttachmentWithUrl }) { const [isDownloading, setIsDownloading] = useState(false); @@ -129,7 +132,6 @@ export function ChatMessageBubble({ message, avatarURL }: ChatMessageBubbleProps {hasImage ? (