1

React newbie here,

EDIT: Sorry, I forgot to add the eventListener code. Then render will just output {this.state.songs}. This is separate from the code I posted above and from a modified version of the code I posted above.

import React, { Component } from 'react';

class AudioList extends Component {
    constructor (props) {
        super(props);

        this.state = {
            songs: ''
        }

        this.audios = [];
        for (let i = 0; i < this.props.songs.length; i++) {
            this.audios.push(new Audio(this.props.songs[i].song_url));
        }
    }

    componentWillMount() {
        const songs = [];
        for (let i = 0; i < this.props.songs.length; i++) {
            this.audios[i].addEventListener('play', () => console.log('Play'));
            songs.push(
                <div className='song-preview'>
                    <button className='preview' onClick={() => this.toggle(this.audios[i])}>Preview {i}</button>
                </div>
            )
        }

        this.setState({
            songs: songs
        })

    }

    componentWillUnmount() {
        for (let i = 0; i < this.props.songs.length; i++) {
            this.audios[i].pause();
        }
    }

    getCurrentAudio () {
        return this.audios.find(audio => false === audio.paused);
    }

    toggle (nextAudio) {
        const currentAudio = this.getCurrentAudio();

        if (currentAudio && currentAudio !== nextAudio) {
            currentAudio.pause();
            nextAudio.play();
        }

        nextAudio.paused ? nextAudio.play() : nextAudio.pause();
    }

    render () {
        if (this.state.songs) {
            return (
                <div className='song-list'>
                    { this.state.songs }
                </div>
            )
        } else {
            return (
                <div className='song-list'></div>
            )
        }
    }
}


export default AudioList;

I am using this code from a previous solution that I found on Stackoverflow (https://stackoverflow.com/a/50595639). I was able to implement this solution to solve my own challenge of needing to have multiple audio sources with one audio player and multiple buttons. However, I am now faced with a new challenge - I want a specific button's text to change when an event is fired up.

I was thinking about implementing state that contains the text for the button that changes when an event fires up, but that wont work because every button will be reading off of the same variable in state and re-rendering, I only want one button to re-render.

I was also thinking about having multiple variables in state that control each specific button, but given that my modified implementation has an dynamic number of audio sources, I don't know the number of state variables I will need.

Does anyone have any suggestions?

Nate
  • 314
  • 1
  • 2
  • 11
  • What event are you referring to? What do you want to change about the button text? – fubar Jul 07 '20 at 02:51
  • Oops, sorry, I didn't include the modified code in the code section above. Basically I moved this section of the code `
    { this.audios.map((audio, index) => ) }
    ` into componentWillMount and stored the output into an array that is stored in state so that I could add event listeners to every Audio object that's created. When an event is fired for a certain Audio object, I want its button to change.
    – Nate Jul 07 '20 at 02:55
  • It sounds like you just need another level of abstraction. Make an `AudioButton` component that accepts a sound file as a prop and changes its own text when you click on it. – Elan Hamburger Jul 07 '20 at 02:57
  • @fubar Sorry about that. I edited the original post so it contains the event listener. Basically instead of it outputting to the console 'Playing', I want the button text to change instead. – Nate Jul 07 '20 at 03:09
  • @ElanHamburger Sorry, I just edited my original post and added the eventListeners. Do you think your suggestion would still stand true given the code that I added? – Nate Jul 07 '20 at 03:10
  • I'm a little confused, you seem to be converting the songs into components in both the `componentWillMount` and `render` functions. Maybe a better solution is to just render the text in the button based on the `Audio` state when you perform the `map`. – Elan Hamburger Jul 07 '20 at 03:19
  • @ElanHamburger Okay, I edited it one more time and replaced everything with my own modified code to prevent anymore confusion. Sorry about that. – Nate Jul 07 '20 at 03:28

1 Answers1

0

Thomas from my secondary thread was kind enough to re-factor my code and essentially re-write parts of it to fix this issue.

You can read his solution here: https://stackoverflow.com/a/62769376/8888293

Nate
  • 314
  • 1
  • 2
  • 11