Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(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')
);
like image 450
theseboys Avatar asked Apr 23 '17 22:04

theseboys


2 Answers

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>
like image 176
Anurag Sharma Avatar answered Nov 09 '22 22:11

Anurag Sharma


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>
like image 23
mrinalmech Avatar answered Nov 09 '22 23:11

mrinalmech