(React js) Audio src is updating on setState but the audio playing doesn’t change

I am trying to build a mini 2-track audio player with React. The audio is centrally controlled by a html audio element with a track-list inside a child component. The (yet to be styled) player can be seen here.

I can tell in the React dev tools that clicking the individual track select buttons does update the src of the audio element (thanks to the help of a member on here), however, the playing audio doesn’t change. I’ve posted the Application code below.

Is it even possible to change the playing audio by updating the state in this way? Help would be hugely appreciated.

var TRACKLIST = [
    {
        id: 1,
        name: "song a",
        source: "./audio/test.m4a"
    },
    {
        id: 2,
        name: "song b",
        source: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/wwy.mp3"
    }
]

function Track(props) {
    return (
        <div className="track">
            <div className="meta">
                <div className="name">
                    <h2>{props.name}</h2>
                </div>
                <audio>
                    <source src={props.source} />
                </audio>
            </div>
            <button className="select" onClick={function() {props.onChange(props.source);}} >
            </button>
        </div>
    )
}

var Application = React.createClass({

    getInitialState: function() {
        return {
            isPlaying: "./audio/test.m4a"
        };
    },

    onTrackChange: function(source) {
        this.setState({ isPlaying: source })
    },

    render: function() {
        return (
            <div className="player">
                <div className="tracklist">
                    {this.props.tracklist.map(function(track){
                        return <Track
                                    key={track.id}
                                    name={track.name}
                                    source={track.source}
                                    onChange={this.onTrackChange} />
                    }.bind(this))}
                </div>
                <div className="controls">
                    <audio controls>
                        <source src={this.state.isPlaying} />
                    </audio>
                </div>
            </div>
        )
    }
});

// Render the UI
ReactDOM.render(
    <Application tracklist={TRACKLIST} />,
    document.getElementById('Player')
);

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Audio files cannot be changed by just changing the src like an image as there is caching. You will need to load it and play it again.

onTrackChange: function(source) {
       this.setState({ isPlaying: source },function(){
            this.refs.audio.pause();
            this.refs.audio.load();
            this.refs.audio.play();
       })
}

The callback handles the pausing, loading and playing after the state has been changed. Remember to add a ref to the audio tag.
<audio controls ref="audio">
   <source src={this.state.isPlaying} />
</audio>

Method 2

Using Hooks

import useRef and create a instance of it.

import React, { useRef } from 'react';
const audioRef = useRef()

Function to update song.
const updateSong = (source) => {
    setSource(source);
    if(audioRef.current){
        audioRef.current.pause();
        audioRef.current.load();
        audioRef.current.play();
    }
}

Don’t forget to add ref to audio tag.
<audio controls ref={audioRef}>
    <source src={source} type='audio/mpeg' />
</audio>

Method 3

Setting different key-attributes on the audio-tag depending on the source works if you are okay with loosing the playing state and time.

Method 4

Using KEY

Actually I think the best way to solve this problem is just add a ‘key‘ attribute:

<audio key={props.id}>
    <source src={props.source}/>
</audio>


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x