I am building a Music Player project in React/Redux and am having some issues with the Prev/Next buttons... I can't really pinpoint exactly what is causing the issue, but the following is my goal:
Previous button: Should always play the last song played before the currently playing song.
Next button: Should play the next song on the playlist.
I am able to achieve each functionality separately, meaning if i make an n-number of song selections, and hit previous n-number of times (in any order), I am getting the correct list of songs previously played. The issue arises when I press both the next and previous buttons in random order. I get a whole jumbled mess of songs instead of the correct orders.
So this is my workflow, just so that you get a better understanding of what is going on here so far:
- On song click - sends up the current song object as a dispatched action to the store
{current}. - We send the same currently selected song up to the store into a
previously_playedarray so that we have a log/history of previously played songs. - The rest of the action happens in the
dashboard.jsfile shown below with comments.
My goal: To get the previous button to log all the previously played songs, then on next-button-press, should go down the regular playlist and play the songs. Also, if the current song is the last song in the list, start again from the first in the playlist (vice versa). Any help would be awesome guys! Thanks in advance.
I have used redux, and here is my code:
REDUCER:
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;
}
}
ACTIONS:
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
});
DASHBOARD:
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);