I'm adding a music-player component/functionality to this react native app. I'm gonna include all the relevant code to give you the best understanding of the setup.
In MusicContext.js, the context file that handles the logic for the music player, I have a few State objects for determining which song to play.
const initialState = {
startMusic: () => null,
stopMusic: () => null,
soundObject: null,
isPlaying: false,
currentIndex: 0
}
My songs array:
mainTheme = new Audio.Sound()
mainTheme2 = new Audio.Sound()
mainTheme3 = new Audio.Sound()
const songs = [
{ path: require("../assets/sounds/MainTheme.mp3"), song: mainTheme },
{ path: require("../assets/sounds/MainTheme2.mp3"), song: mainTheme2 },
{ path: require("../assets/sounds/MainTheme3.mp3"), song: mainTheme3 },
]
currentIndex begins at 0 so the music player will start at songs[0].
The function to start playing the music is as follows:
const startMusic = async () => {
try {
const songToPlay = songs[currentIndex].song // first song in the array of songs
const source = songs[currentIndex].path // the path that loadAsync() function needs to load file
await songToPlay.loadAsync(source)
await songToPlay.playAsync()
setSoundObject(songToPlay)
setIsPlaying(true)
return new Promise(resolve => {
songToPlay.setOnPlaybackStatusUpdate(playbackStatus => {
if (playbackStatus.didJustFinish) {
console.log("Song finished")
resolve()
}
})
})
} catch (error) {
console.log(`Error: ${error}`)
return
}
}
At this point, soundObject = the song that is playing, and currentIndex = 0. My function for skipping to the next song is:
const handleNextTrack = async () => {
if (soundObject) {
await soundObject.stopAsync()
await soundObject.unloadAsync()
setSoundObject(null)
currentIndex < songs.length - 1 ? (currentIndex += 1) : (currentIndex = 0)
setCurrentIndex({ currentIndex })
this.startMusic()
}
}
After that, it goes back to startMusic(), except now with the currentIndex being 1, which should play the next song in the array.
THE ERROR I'M GETTING is
Possible Unhandled Promise Rejection (id: 5): Error: "currentIndex" is read-only
I tried a few different ways of implementing handleNextTrack but it all leads to the same error.
UPDATE
const handlePreviousTrack = async () => {
if (soundObject) {
await soundObject.stopAsync()
await soundObject.unloadAsync()
setSoundObject(null)
let newIndex = currentIndex
newIndex < (songs.length - 1) ? (--newIndex) : (newIndex = 0)
setCurrentIndex(newIndex)
startMusic()
}
}
const handleNextTrack = async () => {
if (soundObject) {
await soundObject.stopAsync()
await soundObject.unloadAsync()
setSoundObject(null)
let newIndex = currentIndex
newIndex < (songs.length - 1) ? (++newIndex) : (newIndex = 0)
setCurrentIndex(newIndex)
startMusic()
}
}
Song[0] plays when app opens. <~GOOD
Song[0] plays again when I hit next <~BAD
Song[1] plays only if I hit next a second time <~GOOD
Song[2] plays if I hit next again <~GOOD
After that I can cycle through a bit, hitting previous and next a few times, but it just broke and somehow the soundObject is back to null