React Native(Expo)数组场景下Expo Video的useRef使用及重渲染重置问题
解决方案
问题根因
- 单ref覆盖:你当前使用单个全局
videoref,循环渲染多个Video组件时,后渲染的视频实例会覆盖前一个存到ref里的实例,因此只有最后一个视频可以正常控制播放。 - 子组件重渲染重置:之前封装子组件出现视频重置,是因为父组件状态更新触发重渲染时,子组件没有做重渲染拦截,导致子组件被卸载后重新挂载,视频恢复到初始状态。另外你原有代码中视频格式判断逻辑存在语法错误,所有媒体都会被识别为视频格式。
实现方案
1. 封装独立视频子组件,用React.memo避免不必要重渲染
子组件内部自己维护ref、播放状态,只要传入的视频地址等核心props不变,父组件其他状态更新不会触发子组件重渲染,也就不会重置视频进度。
import React, { memo, useRef, useState } from 'react'; import { TouchableOpacity } from 'react-native'; import Video from 'expo-video'; // 替换为你实际引入的Video组件路径 const VideoItem = memo(({ videoUrl }) => { const videoRef = useRef(null); const [isPlaying, setIsPlaying] = useState(false); const togglePlay = async () => { if (isPlaying) { await videoRef.current.pauseAsync(); } else { await videoRef.current.playAsync(); } }; return ( <TouchableOpacity onPress={togglePlay} style={{ flex: 1 }}> <Video ref={videoRef} style={{ alignSelf: 'center' }} source={{ uri: videoUrl }} onPlaybackStatusUpdate={(status) => { setIsPlaying(status.isPlaying); }} /> </TouchableOpacity> ); }); export default VideoItem;
2. 修正父组件逻辑,补充稳定key、修正格式判断
import React, { useState } from 'react'; import { SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar, Image, } from 'react-native'; import VideoItem from './VideoItem'; function App(props) { const [allData, setAllData] = useState([ { medias: [ { link: 'https://link.com/link1.avi', mediaExtension: 'avi' }, { link: 'https://link.com/link2.jpg', mediaExtension: 'jpg' }, { link: 'https://link.com/link3.mov', mediaExtension: 'mov' }, ], name: 'Name', description: 'description', }, ]); // 定义支持的视频格式数组 const VIDEO_EXTENSIONS = ['mov', 'avi', 'WebM']; return ( <View style={{}}> <FlatList horizontal data={allData} keyExtractor={(item, index) => `group-${index}`} renderItem={({ item }) => ( <View style={{}}> {item.medias.map((media, index) => ( // 必须给循环项加稳定的唯一key,避免React误删组件导致重置 <View key={`media-${media.link || index}`}> {VIDEO_EXTENSIONS.includes(media.mediaExtension) ? ( <VideoItem videoUrl={media.link} /> ) : ( <Image style={{}} source={{ uri: media.link }} /> )} </View> ))} </View> )} /> </View> ); } export default App;
关键优化点说明
React.memo会对传入子组件的props做浅比较,只要视频地址没有变化,子组件就不会触发重渲染,自然不会重置视频播放进度。- 所有循环渲染的项都必须加稳定唯一的key,避免React在diff时错误复用/卸载组件,导致视频被重置。
- 修正了原有视频格式判断的逻辑错误,不会再把图片识别为视频渲染。
内容的提问来源于stack exchange,提问作者flaneurx
相关产品推荐
相关产品推荐

