我正在尝试循环浏览数组中的声音对象,使用从 0 开始的索引值,并根据我按下一步还是向后递增/递减。
这适用于使用 Expo//expo-av 库的 react-native 音乐播放器。我将包括所有相关代码。
我在上下文文件中的状态:
const initialState = {
startMusic: () => null,
stopMusic: () => null,
soundObject: null,
isPlaying: false,
currentIndex: 0,
}
useState()
const [soundObject, setSoundObject] = useState(initialState.soundObject)
const [isPlaying, setIsPlaying] = useState(initialState.isPlaying)
const [currentIndex, setCurrentIndex] = useState(initialState.currentIndex)
启动音乐功能
const startMusic = async () => {
try {
const songToPlay = songs[currentIndex].song
const source = songs[currentIndex].path
await songToPlay.loadAsync(source)
await songToPlay.playAsync()
setSoundObject(songToPlay)
setIsPlaying(true)
return new Promise(resolve => { // I made this promise when I was setting a loop to play through music. May not need this anymore
songToPlay.setOnPlaybackStatusUpdate(playbackStatus => {
if (playbackStatus.didJustFinish) {
console.log("Song finished")
resolve()
}
})
})
} catch (error) {
console.log(`Error: ${error}`)
return
}
}
最后,应该循环播放歌曲的处理程序函数:
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()
console.log(currentIndex)
}
}
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()
console.log(currentIndex)
}
}
循环浏览下一个/上一个不按顺序进行。 有时它有效,有时上一首转到下一首歌曲,有时按下一首只是重播第一首歌曲。
我是否错误地通过当前索引操纵状态?
通过快速浏览,我没有看到上面的代码中有任何惊人的错误。 我的一个建议是将startMusic()
调用从两个handleTrack
方法中删除,而是让它们像现在一样设置索引状态。
而是添加一个每次索引更改时都会触发的useEffect
,并将startMusic()
置于该 useEffect 中。
它看起来像这样:
useEffect(() => {
... (other logic)
startMusic()
}, [currentIndex])
这将确保startMusic只会在当前索引状态更改后被调用,并且不会太快被调用等。 如果不是,则无论状态何时更改,都可以更轻松地跟踪