In my react-native project, I'm using react-navigation 5 for navigation and react-native-video for a audio/video player.
My requirement is that when a user navigates to another scren, if the audio/video should stop playing. However, that's not happening and the audio keeps playing.
I have created two screens in a stack navigator. The Video Player is a separate component.
Screen Code:
function MainScreen({ navigation }) {
const [audiostatus, setAudioStatus] = useState(true);
React.useEffect(() => {
const unsubscribe = navigation.addListener('blur', () => {
console.log('Leaving Home Screen');
setAudioStatus(true);
});
return unsubscribe;
}, [navigation]);
return (
<View style={{ flex: 1, justifyContent: 'center',backgroundColor: '#fff' }}>
<Player tracks={TRACKS} paused={audiostatus} />
<Button
title="Go to Screen Without Audio"
onPress={() => navigation.navigate('No Audio Screen')}
/>
<Button
title="Go to Screen With Another Audio (Love Yourself)"
onPress={() => navigation.navigate('Another Audio Screen')}
/>
</View>
);
}
Player Code Within the Player, I recieve the paused prop to decide whether the video should be already playing or paused. Then the player has controls that control the playbck by changing the state.
export default class Player extends Component {
constructor(props) {
super(props);
this.state = {
paused: props.paused,
totalLength: 1,
currentPosition: 0,
selectedTrack: 0,
repeatOn: false,
shuffleOn: false,
};
}
setDuration(data) {
this.setState({totalLength: Math.floor(data.duration)});
}
setTime(data) {
this.setState({currentPosition: Math.floor(data.currentTime)});
}
seek(time) {
time = Math.round(time);
this.refs.audioElement && this.refs.audioElement.seek(time);
this.setState({
currentPosition: time,
paused: false,
});
}
render() {
const track = this.props.tracks[this.state.selectedTrack];
const video = this.state.isChanging ? null : (
<Video source={{uri: track.audioUrl}} // Can be a URL or a local file.
ref="audioElement"
paused={this.state.paused} // Pauses playback entirely.
resizeMode="cover" // Fill the whole screen at aspect ratio.
repeat={false} // Repeat forever.
onLoadStart={this.loadStart} // Callback when video starts to load
onLoad={this.setDuration.bind(this)} // Callback when video loads
onProgress={this.setTime.bind(this)} // Callback every ~250ms with currentTime
onEnd={this.onEnd}
onError={this.videoError}
style={styles.audioElement}
audioOnly={true} />
);
return (
<View style={styles.container}>
<SeekBar
onSeek={this.seek.bind(this)}
trackLength={this.state.totalLength}
onSlidingStart={() => this.setState({paused: true})}
currentPosition={this.state.currentPosition} />
<Controls
onPressPlay={() => this.setState({paused: false})}
onPressPause={() => this.setState({paused: true})}
paused={this.state.paused}/>
{video}
</View>
);
}
}
The problem is that once a user starts playing the video, and then if he navigates to another screen, the video keeps playing. I want the video to pause. In the screen, i've added useEffect() to set audiostatus to pause on screen blur, but nothing happens. The video keeps playing. Please help.
Do the following way to pause the video
import React, {useState, useRef} from 'react';
function MainScreen({ navigation }) {
const [audiostatus, setAudioStatus] = useState(true);
// create ref
const playerRef = useRef();
React.useEffect(() => {
const unsubscribe = navigation.addListener('blur', () => {
console.log('Leaving Home Screen');
setAudioStatus(false);
// new code add to pause video from ref
playerRef.current.pauseVideo();
});
return unsubscribe;
}, [navigation]);
return (
<View style={{ flex: 1, justifyContent: 'center',backgroundColor: '#fff' }}>
<Player ... playerRef={playerRef} />
</View>
);
}
Convert Player class into Hooks as I did
import React, {useState, useImperativeHandle, useRef} from 'react';
function Player = (props) => {
const [paused, setPaused] = useState(props.paused);
const [totalLength, setTotalLength] = useState(1);
const [currentPosition, setCurrentPosition] = useState(0);
const [selectedTrack, setSelectedTrack] = useState(0);
const [repeatOn, setRepeatOn] = useState(false);
const [shuffleOn, setShuffleOn] = useState(false);
const [isChanging, setIsChanging] = useState(false);
const audioElement = useRef(null);
const setDuration = (data) => {
setTotalLength(Math.floor(data.duration));
}
const setTime = (data) => {
setCurrentPosition(Math.floor(data.currentTime));
}
const seek = (time) => {
time = Math.round(time);
audioElement && audioElement.current.seek(time);
setCurrentPosition(time);
setPaused(false);
}
const loadStart = () => {}
// add for accessing ref
useImperativeHandle(props.playerRef, () => ({
pauseVideo: () => setPaused(true),
}));
const track = props.tracks[selectedTrack];
const video = isChanging ? null : (
<Video source={{uri: track.audioUrl}} // Can be a URL or a local file.
ref={audioElement}
paused={paused} // Pauses playback entirely.
resizeMode="cover"
....
onLoadStart={loadStart} // new added
onLoad={setDuration} // new added
/>
);
return (
<View style={styles.container}>
<SeekBar
onSeek={seek}
trackLength={totalLength}
onSlidingStart={() => setPaused(true)}
currentPosition={currentPosition} />
<Controls
onPressPlay={() => setPaused(false) }
onPressPause={() => setPaused(true)}
paused={paused}/>
{video}
</View>
);
}