React Native中React Navigation beforeRemove调用Video播放时长方法的问题
解决方案
要实现关闭Page页面时获取视频播放时长,核心是让Page组件能访问Video组件的方法,同时在页面即将移除时触发统计逻辑,具体步骤如下:
1. 改造Video组件,暴露播放时长方法
函数组件默认不支持ref,需用forwardRef和useImperativeHandle将getSeconds方法暴露给父组件:
// Video.js import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react'; import { Video } from 'expo-av'; import ExpoVideoPlayer from 'expo-video-player'; const VideoComponent = forwardRef((props, ref) => { const video = useRef(null); const [secondsPlayed, setSecondsPlayed] = useState(0); // 监听播放进度,实时更新播放时长 const onPlaybackStatusUpdate = (status) => { if (status.isPlaying) { setSecondsPlayed(Math.floor(status.positionMillis / 1000)); } }; // 定义要暴露的方法 const getSeconds = () => { return secondsPlayed; }; // 向父组件暴露方法 useImperativeHandle(ref, () => ({ getSeconds })); return ( <ExpoVideoPlayer videoProps={{ resizeMode: Video.RESIZE_MODE_STRETCH, source: { uri: props.videoUrl }, onPlaybackStatusUpdate: onPlaybackStatusUpdate }} inFullscreen={false} showControlsOnLoad={true} videoBackground="#fff" height={200} videoRef={video} showFullscreenButton={false} playIcon={() => props.playIcon} replayIcon={() => props.replayIcon} pauseIcon={() => props.pauseIcon} sliderColor="#CE4A52" /> ); }); export default VideoComponent;
2. 在Page组件中关联Video实例并监听页面移除事件
在Page组件中创建ref绑定Video组件,通过navigation.addListener监听beforeRemove事件,调用Video的方法获取时长:
// Page.js import React, { useRef, useEffect } from 'react'; import { SafeAreaView } from 'react-native'; import VideoComponent from './Video'; const Page = ({ navigation }) => { const videoRef = useRef(null); useEffect(() => { // 添加页面移除监听 const unsubscribe = navigation.addListener('beforeRemove', () => { const playedSeconds = videoRef.current?.getSeconds(); console.log('视频播放时长:', playedSeconds, '秒'); }); // 组件卸载时清理监听器 return unsubscribe; }, [navigation]); return ( <SafeAreaView> {/* 传递ref给Video组件 */} <VideoComponent ref={videoRef} videoUrl="你的视频地址" playIcon={/* 自定义播放图标 */} replayIcon={/* 自定义重播图标 */} pauseIcon={/* 自定义暂停图标 */} /> </SafeAreaView> ); }; export default Page;
3. 移除导航配置中的beforeRemove监听器
由于已在Page内部实现监听,Stack导航配置里的对应代码可删除:
// Stack导航配置 <Stack.Screen name="Page" component={Page} options={{ headerShown: false }} // 移除原listeners配置 />
关键说明
- 导航层的
beforeRemove监听器无法直接访问Page内部的子组件实例,将逻辑移到Page组件内更合理。 forwardRef+useImperativeHandle是函数组件间实现父调用子方法的标准方式。- 必须通过
onPlaybackStatusUpdate实时更新播放时长,确保获取的是最新数据。
内容的提问来源于stack exchange,提问作者jNiuk
相关产品推荐
相关产品推荐

