1
\$\begingroup\$

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.

  1. goToNextSound- The currentSoundIndex is incremented

  2. 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:

  1. 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?
  2. 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;
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.