我正在React/Redux中构建一个音乐播放器项目,并且上一个/下一个按钮有一些问题。。。我无法确切指出问题的原因,但我的目标是:
“上一步”按钮:应始终播放当前播放歌曲之前播放的最后一首歌曲。
下一步按钮:应播放播放列表中的下一首歌曲。
我能够分别实现每个功能,这意味着如果我选择了n首歌曲,并按了前n首歌曲的次数(以任何顺序),我将获得以前播放的歌曲的正确列表。当我随机按“下一步”和“上一步”按钮时,问题就出现了。我收到一大堆乱七八糟的歌曲,而不是正确的顺序。
这是我的工作流程,只是为了让你更好地了解到目前为止这里发生了什么:
previously_played
数组,以便我们有以前播放过的歌曲的日志/历史记录。dashboard.js
文件中,并附有注释。我的目标是:让“上一步”按钮记录所有以前播放的歌曲,然后按下“下一步”按钮,应进入常规播放列表并播放歌曲。此外,如果当前歌曲是列表中的最后一首歌曲,请从播放列表中的第一首歌曲重新开始播放(反之亦然)。任何帮助都是很棒的家伙!提前谢谢。
我使用了redux,下面是我的代码:
减速器:
import { CURRENT, PREV, NEXT, PLAYLIST, PREVIOUSLY_PLAYED } from '../actions/action_types';
const initial_state = {
playlist: [],
previously_played: [],
current_song: {},
prev_song: {},
next_song: {},
}
export default function songs_reducer (state = initial_state, action) {
switch(action.type) {
case PLAYLIST:
return {
...state,
playlist: action.payload
}
case PREVIOUSLY_PLAYED:
return {
...state,
previously_played: [...state.previously_played, action.payload]
}
case CURRENT:
return {
...state,
current_song: action.payload
}
case PREV:
return {
...state,
prev_song: action.payload
}
case NEXT:
return {
...state,
next_song: action.payload
}
default:
return state;
}
}
行动:
import { PLAYLIST, PREVIOUSLY_PLAYED, CURRENT, PREV, NEXT, CURRENT_ELEMENT } from './action_types';
export const playlist = data => ({
type: PLAYLIST,
payload: data
});
export const previously_played = data => ({
type: PREVIOUSLY_PLAYED,
payload: data
});
export const current = data => ({
type: CURRENT,
payload: data
});
export const prev = data => ({
type: PREV,
payload: data
});
export const next = data => ({
type: NEXT,
payload: data
});
export const current_element = data => ({
type: CURRENT_ELEMENT,
payload: data
});
仪表板:
import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { playlist, previously_played, current, prev, next, current_element } from '../../redux/actions/actions';
// IMPORT COMPONENTS
import ControlsWidget from '../global/controls/controls.js';
import InfoWidget from '../global/info-widget/info_widget.js';
const Dashboard = (props) => {
const [playing_track, set_playing_track] = useState({}); // CURRENTLY PLAYING SONG
const [previous_song_name, set_previous_song_name] = useState('');
const [previous_song, set_previous_song] = useState('');
// COUNTER TO TRAVERSE BACKWARDS FOR PREVIOUS LOG
let [counter, set_counter] = useState(1);
// ON CURRENT TRACK UPDATE, SET THE CURRENTLY PLAYING TRACK DATA TO STATE, KEEPING IT GENERIC
useEffect(() => {
set_playing_track({track: props.current_track.track, url: props.current_track.url});
}, [props.current_track]);
// SHOW PREVIOUS SONG
const show_previous = () => {
console.log('CURRENT TRACK (PREV BTN)', playing_track);
// console.log('PREVIOUSLY PLAYED SONGS', props.previously_played_songs);
counter++;
set_counter(counter);
let prev_url = props.previously_played_songs[props.previously_played_songs.length - (counter)].url;
let prev_track = props.previously_played_songs[props.previously_played_songs.length - (counter)].track;
// console.log('PREVIOUS SONG ', prev_url, prev_track);
set_playing_track({track: prev_track, url: prev_url});
// SET CURRENT
props.current(props.previously_played_songs[props.previously_played_songs.length - (counter)]);
}
// SHOW NEXT SONG
const show_next = () => {
console.log('CURRENT TRACK (NXT BTN)', props.current_track);
// LOOP OVER PLAYLIST AND SET NEXT SONG
for (let i = 0; i < props.all_songs.length; i++) {
if (((props.current_track.url.localeCompare(props.all_songs[i].url)) === 0)) {
// SET AS CURRENT IN REDUX STORE
props.current(props.all_songs[i + 1]);
// PUSH IN PREVIOUSLY PLAYED LOG
props.previously_played(props.all_songs[i + 1]);
// SET AS CURRENTLY PLAYING GENERIC STATE VARIABLE
set_playing_track({track: props.all_songs[i + 1].track, url: props.all_songs[i + 1].url});
}
}
}
return (
<aside className='sec-std' id='main-dashboard'>
<InfoWidget track_name={playing_track.track}/>
<ControlsWidget url={playing_track.url} show_previous={show_previous} show_next={show_next} />
</aside>
)
}
const mapStateToProps = (state) => {
return {
current_track: state ? state.songs.current_song : null,
previously_played_songs: state ? state.songs.previously_played : null,
all_songs: state ? state.songs.playlist : null
}
}
export default connect(mapStateToProps, {current, previously_played})(Dashboard);
这其实是一个算法问题,我觉得。
我认为我们需要先举一些例子。
假设播放列表是静态的,比如[0,1,2,3,4,5,6,7]
。
然后假设用户可以随机播放任何一首歌曲,并且在当前歌曲结束后自动播放下一首歌曲。
现在考虑一些序列:
Step 1, play 4
=> history=[4], cur=4, prev=undefined, next=5
Step 2, just let 4 plays until the end, then 5 automatically plays, so that:
=> history=[4,5], cur=5, prev=4, next=6
Step 3, hit 7 before 5 ends
=> history=[4,5,7], cur=7, prev=5, next=8
Step 4, before 7 ends, hit 4 again
=> history=[5,7,4], cur=4, prev=7, next=5
Step 5, before 4 ends, hit prev, now 7 is the current song
=> history=[5,4,7], cur=7, prev=4, next=8
Step, before 7 ends, hit next, now 8 uis the current song
=> history=[5,4,7,8], cur=8, prev=7, next=undefined
不确定上述示例是否符合您的请求?
如果是,那么算法是:
1. If the current song is not in history array, push it
2. Else if the current song in in history array, erase it, then push it
(So that current song is actually always history[length - 1])
3. So the prev song is actually always history[length - 2]
4. Next song is always playlist[current song's index +1]