React Native导航切换时音视频无法暂停问题求助
嘿,我一眼就揪出问题所在了——你的Player组件没有同步父组件传过来的paused属性变化!
问题根源
你的Player是class组件,它的paused状态只在构造函数初始化阶段从props里读取了一次。当MainScreen里的audiostatus因为导航blur事件变成true时,虽然传给Player的paused props已经改变,但Player内部的state.paused还是停留在初始值,导致<Video>组件的paused属性压根没更新,音频自然就继续播放了。
两种可行的解决思路
思路一:同步props到state(快速修复)
给Player组件添加componentDidUpdate生命周期方法,监听props.paused的变化,一旦发现差异就更新内部state:
export default class Player extends Component { constructor(props) { super(props); this.state = { paused: props.paused, // 其他状态保持不变... }; } // 添加这个方法,监听props变化 componentDidUpdate(prevProps) { if (prevProps.paused !== this.props.paused) { this.setState({ paused: this.props.paused }); } } // 其他原有方法保持不变... }
这样当MainScreen的audiostatus变化时,Player会自动同步状态,<Video>组件的播放状态就会跟着暂停了。
思路二:让父组件完全控制播放状态(更推荐,符合React单向数据流)
既然MainScreen已经在管理播放状态,不如把Player的paused状态完全交给父组件控制,彻底避免内部state和props不一致的问题:
先修改
Player组件:- 删掉state里的
paused字段 - 所有用到
this.state.paused的地方替换成this.props.paused - 播放/暂停按钮的点击事件改成通知父组件更新状态:
export default class Player extends Component { constructor(props) { super(props); this.state = { // 保留其他状态,移除paused totalLength: 1, currentPosition: 0, selectedTrack: 0, repeatOn: false, shuffleOn: false, }; } // 修改seek方法,不需要再设置paused到state,而是通知父组件 seek(time) { time = Math.round(time); this.refs.audioElement && this.refs.audioElement.seek(time); this.setState({ currentPosition: time }); // 拖动进度条后自动播放,通知父组件更新状态 this.props.onPlayPauseChange(false); } render() { const track = this.props.tracks[this.state.selectedTrack]; const video = this.state.isChanging ? null : ( <Video source={{uri: track.audioUrl}} ref="audioElement" // 直接使用props传递的paused状态 paused={this.props.paused} // 其他属性保持不变... /> ); return ( <View style={styles.container}> <SeekBar onSeek={this.seek.bind(this)} trackLength={this.state.totalLength} onSlidingStart={() => this.props.onPlayPauseChange(true)} currentPosition={this.state.currentPosition} /> <Controls // 点击按钮时通知父组件切换状态 onPressPlay={() => this.props.onPlayPauseChange(false)} onPressPause={() => this.props.onPlayPauseChange(true)} paused={this.props.paused}/> {video} </View> ); } }- 删掉state里的
然后修改
MainScreen里的Player调用,传入状态更新的回调:
<Player tracks={TRACKS} paused={audiostatus} onPlayPauseChange={setAudioStatus} />
这样所有播放状态都由MainScreen统一管理,导航离开时设置audiostatus=true,Player会立刻响应这个变化,暂停音频播放。
验证效果
修改完成后,你可以测试一下:播放音频,点击按钮跳转到其他屏幕,此时控制台会打印Leaving Home Screen,audiostatus变成true,Player接收到paused=true后,<Video>组件就会自动暂停播放了。
内容的提问来源于stack exchange,提问作者asanas

