I built a simple MP3 player with React and now I would like to incorporate Redux to the app as it is getting larger and I feel Redux will help it to be more organized and efficient.
I was wondering can you look through my code and help me with a few questions I have (which you will see shortly).
Firstly I will tell you a bit of information on how the simple React version of the app is working:
I have a state called currentSoundIndex which is initialized to 0 as follows:
getInitialState: function () {
return {
currentSoundIndex: 0
}
}
and this is the main state which changes throughout the application when various methods are called e.g.
goToNextSound- The currentSoundIndex is incremented
goToPreviousSound- The currentSoundIndex is decremented
I also have a selectSound method which is called when a sound list item is selected.
<li className="sound-info-area" onClick={props.selectSound.bind(null, i)}>
<span className="sound-title">{sound.title}</span>
<span className="sound-artist">{sound.artist}</span>
</li>
The index of the list item is passed in to the selectSound method and used to set the new currentSoundIndex as follows.
selectSound: function(i){
//if user selects a sound then we should firstly stop the player.
this.stopPlayer();
//set the currentSoundIndex state to be the index of the selected list item
this.setState({currentSoundIndex: i}, () => {
//we need to load the player as a new src has been inserted to the Audio tag after the currentSoundIndex state was updated.
this.loadPlayer();
if(this.state.isPlaying){
//if the player is in a state of playing then play the sound
this.playSound();
}
});
}
The Redux version of the app
Now I am re-arranging the application in order to incorporate Redux and I was wondering can I get your advice on the following:
- Firstly I'm not sure where I should put the "player" logic. I.e I have the stopPlayer() function in my Action creator. Is it ok to have it there?
- Also, (in a similar way to the selectSound(i) function in the React version of the app), I have created an Action called selectSound. I have also created a reducer to listen for this action. My question is can I create a callback for when this reducer has finished updating the currentSoundIndex state after the action has occured? So that I can call functions such as loadplayer() and playSound().
Here is my SoundsList component/container
import {selectSound} from '../actions/select-sound';
//When clicking on a sound item the selectSound Action creator function is called in order to update the currentSoundIndex.
//after the currentSoundIndex state is updated we should then load the player again and play the sound.
const SoundsList = function(props) {
return (<div className="scrollable-container scrollable">
<div id="list-of-sounds-container">
<ul id="list-of-sounds">
{props.sounds.map((sound, i) => {
return (<li key={sound.id} className={"sound-list-item " + (props.currentSoundIndex === i ? 'selected' : 'not-selected')}>
<span className="sound-info-area" onClick = {() => props.selectSound(i)}>
<span className="sound-title">{sound.title}</span>
<span className="sound-artist">{sound.artist}</span>
</span>
<button className="btn-inline"><i className="fa fa-heart"></i></button>
</li>
);
})}
</ul>
</div>
</div>
);
}
function mapStateToProps(state){
return{
sounds: state.sounds,
currentSoundIndex: state.currentSoundIndex
};
}
function matchDispatchToProps(dispatch){
return bindActionCreators({selectSound: selectSound}, dispatch)
}
export default connect(mapStateToProps, matchDispatchToProps)(SoundsList);
Action creator-selectSound
export const selectSound = (soundIndex) => {
console.log("you clicked on sound: ", soundIndex);
//firstly stop the player when a new sound is selected
//also will need to call loadPlayer() and playSound() after the currentSoundIndex reducer is updated
this.stopPlayer();
return {
type: 'SOUND_SELECTED',
payload: soundIndex
};
};
Reducer- reducer-current-sound.js
export default function (state=null, action) {
//listen for the action type
//if the action type is SOUND_SELECTED than return the index of the sound that was selected
switch(action.type){
case "SOUND_SELECTED":
return action.payload;
break;
//action.payload will be the index of the sound.
}
return state;
}
The following is the code for combining my reducers into one
import SoundsReducer from './reducer-sounds';
import CurrentSoundReducer from './reducer-current-sound';
const allReducers = combineReducers({
sounds: SoundsReducer,
currentSoundIndex: CurrentSoundReducer
});
export default allReducers;