Solution 1 :

Don’t store jsx in state

Just store the url an name in state and render jsx.

Like this

...
state = {
    url: '',
    name: ''
}
fileLoaded = (event) => {

    const url = URL.createObjectURL(event.target.files[0]);
 
    let react_player = {
        url,
        name: event.target.files[0].name
    };
 
    this.setState({ reactPlayer: react_player });
 
    event.preventDefault();
  };
 
 render() {
 
    return (
      <div>
        <form onSubmit={this.submitAudioFile}>
          <Button
            className="Button"
            size="large"
            variant="contained"
            component="label"
            startIcon={<CloudUploadIcon />}
          >
            Upload File
            <input
              accept="audio/*"
              type="file"
              onChange={this.fileLoaded}
              style={{ display: "none" }}
            />
          </Button>
        </form>
        {/* {this.state.reactPlayer} */}
        {this.state.url && <AudioPlayer url={this.state.url} name={this.state.name} />}
      </div>
    );
  } 

Solution 2 :

Found the solution to this. The trick was to pass props and tampering with the state in the AudioPlayer component.

          <audio
            onLoadedMetadata={(event) => this.audioWasLoaded(event)}
            onEnded={(event) => this.audioEnded(event)}
            onTimeUpdate={(event) => this.audioIsPlaying(event)}
            src={this.props.url}
            ref={this.audioRef}
          />

Just hooked up the src of audio tag to the prop that is passed from the parent component and everything came out fine.

Problem :

I have a audio component that uses a file picker and on it’s onChange event, the state is updated and the audio component is reloaded.

fileLoaded = (event) => {

   const url = URL.createObjectURL(event.target.files[0]);

   let react_player = (
     <AudioPlayer url={url} name={event.target.files[0].name} />
   );

   this.setState({ reactPlayer: react_player });

   event.preventDefault();
 };

render() {

   return (
     <div>
       <form onSubmit={this.submitAudioFile}>
         <Button
           className="Button"
           size="large"
           variant="contained"
           component="label"
           startIcon={<CloudUploadIcon />}
         >
           Upload File
           <input
             accept="audio/*"
             type="file"
             onChange={this.fileLoaded}
             style={{ display: "none" }}
           />
         </Button>
       </form>
       {this.state.reactPlayer}
     </div>
   );
 } 

So every time the file is changed the reactPlayer component is supposed to be re-rendered from the state. But that is not happening and the file loaded into reactPlayer remains the same even after triggering the onChange event.

This is the AudioPlayer component.

  constructor(props) {
    super();
    this.audioRef = React.createRef();
  }

  componentDidMount() {
    this.setState({ audioSource: this.props.url, name: this.props.name });
    console.log(this.props.name);
  }

  state = {
    playing: false,
    source: null,
    currentTime: 0,
    totalTime: 0,
    audioSource: "",
    name: "",
  };

  playOrPauseButton = () => {
    // console.log("CALLED");

    // const styleJson = { color: "#000", fontSize: "50" };

    if (!this.state.playing) {
      return (
        <PlayCircleFilledIcon
          //   style={styleJson}
          className="playPauseButtonHover"
          onClick={this.playOrPause}
        />
      );
    } else {
      return (
        <PauseCircleFilledIcon
          className="playPauseButtonHover"
          //   style={styleJson}
          onClick={this.playOrPause}
        />
      );
    }
  };

  playOrPause = () => {
    // console.log("Hello");
    if (this.state.playing) {
      this.audioRef.current.pause();
      console.log("pause");
    } else {
      this.audioRef.current.play();
      console.log("play");
    }
    const prevPlayingState = this.state.playing;
    this.setState({ playing: !prevPlayingState });
  };

  audioIsPlaying = (e) => {
    this.setState({ currentTime: Math.floor(e.target.currentTime) });
    this.setState({ duration: Math.floor(e.target.duration) });

    // console.log(this.state.currentTime + ":" + this.state.duration);
  };

  audioEnded = (e) => {
    console.log("ended");
    this.setState({ playing: false, currentTime: 0 });
  };

  audioWasLoaded = (e) => {
    this.setState({ duration: Math.floor(e.target.duration) });
    // let x = e.target.src;
  };

  render() {
    let x = this.playOrPauseButton();
    // this.getAudioLength();

    return (
      <div>
        <LinearProgress
          className="top"
          variant="determinate"
          value={(this.state.currentTime * 100) / this.state.duration}
        />
        <div className={styles.audioPlayerDiv}>
          {x}
          <div>
            <p style={{ textAlign: "center" }}>
              {this.state.currentTime}/{this.state.duration}
            </p>

            <p style={{ fontWeight: "bold" }}>{this.state.name}</p>
          </div>

          <audio
            onLoadedMetadata={(event) => this.audioWasLoaded(event)}
            onEnded={(event) => this.audioEnded(event)}
            onTimeUpdate={(event) => this.audioIsPlaying(event)}
            src={this.state.audioSource}
            ref={this.audioRef}
          />

          <NoteAddIcon className="playPauseButtonHover"></NoteAddIcon>
          {/* <button style={{ alignItems: "left" }}>take note</button> */}
        </div>
      </div>
    );
  }
}

export default AudioPlayer;```

Comments

Comment posted by Aniruddha Bera

Tried you solution. The flow of events goes to

By

Leave a Reply

Your email address will not be published. Required fields are marked *