today I wanted to experiment with the audio in the React-native. I want to start my sound and then stop it after 5 sec so i follow instructions in expo website for audio (expo-av) so my code so far looks like that -
const [sound, setSound] = React.useState();
async function playSound() {
console.log("Loading Sound");
const { sound } = await Audio.Sound.createAsync(
require("./assets/sound.mp3")
);
setSound(sound);
console.log("Playing Sound");
await sound.playAsync();
}
React.useEffect(() => {
return sound
? () => {
console.log("Unloading Sound");
sound.unloadAsync();
}
: undefined;
}, [sound]);
.
.
.
<Button
title={"Play"}
onPress={async () => {
await playSound();
setTimeout(async () => {
await sound.stopAsync();
}, 5000);
}}
/>
but i got error
[Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'sound.stopAsync')]
Why? I can`t understad?
CodePudding user response:
If you load the sound when you mount the component the error goes away. Otherwise you have to press the button twice to get some result. Here's demo
import React from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { Audio } from 'expo-av';
export default function App() {
const [sound, setSound] = React.useState();
const [isPlaying, setIsPlaying] = React.useState(false)
async function loadSound(){
console.log('Loading Sound');
const { sound } = await Audio.Sound.createAsync(
require('./assets/sound.mp3')
);
setSound(sound);
}
async function playSound() {
if (!sound) {
await loadSound()
}
console.log(await sound.getStatusAsync());
if(!isPlaying){
console.log('Playing Sound');
await sound.playAsync();
}
else{
await sound.stopAsync();
}
setIsPlaying(prev=>!prev)
}
React.useEffect(()=>{
loadSound()
},[])
React.useEffect(() => {
return sound
? () => {
console.log('Unloading Sound');
sound.unloadAsync();
}
: undefined;
}, [sound]);
return (
<View style={styles.container}>
<Button title={isPlaying ? 'Stop' :"Start"} onPress={playSound} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 8,
},
});