简体   繁体   中英

How to fix issue with audio.play()? in React

I'm trying to implement a button with some sound attached to it in React, but whatever I do I get: 'TypeError: audio.play is not a function'

I tried to create both the element and getting it by id, as well as using plain js with new Audio(src) . In both cases I get error. I checked hundreds of examples online and they all do same way, but somehow my way doesn't work

import React, { Component } from "react";
import { CSSTransition } from "react-transition-group";
import OctagonalButton from "./OctagonalButton";
import  "../../css/buttons/HeroButtons.css";
// import soundfile from "../../internalAsset/sounds/button-1.mp3";
class HeroButtons extends Component {
  constructor(props) {
    super(props);
    this.state = { fadeIn: false, hover: false };
  }

  componentDidMount() {
    this.setState({ fadeIn: true });
    // we add the even listener to buttons
    setTimeout(() => {
      // we add the even listener to buttons
      var button1 = document.querySelector("#HerofindMore1");
      button1.addEventListener("mouseenter", () => {
        this.toggleHover();
      });
      button1.addEventListener("mouseleave", () => {
        this.toggleHover();
      });
      var button2 = document.querySelector("#HerofindMore2");
      button2.addEventListener("mouseenter", () => {
        this.toggleHover();
      });
      button2.addEventListener("mouseleave", () => {
        this.toggleHover();
      });
    }, 600);
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevState.hover !== this.state.hover) {
      if (this.state.hover) {
        // on onMouseEnter we play the Sund
        this.Sound("play");
      } else {
        // if onMouseLeave we stop the sound
        this.Sound("stop");
      }
    }
  }

  handleClick = () => {
    // send the unmounting notification to hero header
    this.props.alertHeroHeader();
    // let the transition do its job before unmount the component
    this.setState({ fadeIn: false });
    // unmount the component
    setTimeout(() => {
      this.props.onClick();
    }, 2000);
  };

  toggleHover = () => {
    this.setState({ hover: !this.state.hover });
  };

  Sound = value => {

    let audio = new Audio("../../internalAsset/sounds/button-1.mp3");

    if (value === "play") {
      console.log("Play");
      console.log(audio);
       audio.play();
    } else {
      audio.pause();
      console.log("Stop");
    }
  };

  render() {
    return (
      <div>        
        <CSSTransition
          in={this.state.fadeIn}
          timeout={{ enter: 500, exit: 500 }}
          classNames={{
            appear: "fade-appear",
            appearActive: "fade-active-appear",
            enter: "fade-enter",
            enterActive: "fade-enter-active",
            enterDone: "fade-enter-done",
            exit: "fade-exit",
            exitActive: "fade-exit-active",
            exitDone: "fade-exit-done"
          }}
          unmountOnExit
          onExited={() => {
            this.props.onClick();
          }}
        >
          <div className="buttonHeroWrapper">
            <OctagonalButton
              type="HeroButtonMore1"
              id="HerofindMore1"
              onClick={this.handleClick}
            />
            <OctagonalButton
              type="HeroButtonMore2"
              id="HerofindMore2"
              onClick={this.handleClick}
            />
          </div>
        </CSSTransition>
      </div>
    );
  }
}
export default HeroButtons;

this is the console.log() of the audio

Audio {name: "audio", uuid: "9B72D3F7-2A6E-459D-A144-285ABACE1B9A", type: "Audio", format: "arraybuffer", encoding: "mp3", …}
data: ArrayBuffer(1862) {}
encoding: "mp3"
format: "arraybuffer"
name: "audio"
type: "Audio"
uuid: "9B72D3F7-2A6E-459D-A144-285ABACE1B9A"
__proto__: Resource

Thanks in advance for the help!

I would suggest to use onMouseEnter and onMouseLeave props on button component, then you don't need to attach events on componentDidMount .

I just created an example you can see here https://codesandbox.io/s/react-mdn-audio-ffgox

But if you want to keep using addEventListener , then you'll need to change arrow functions to normal functions, because this will not refer to the HeroButtons class. Try something like this:

button2.addEventListener("mouseleave", function() {
  this.toggleHover();
});

I encourage you to use stateless components with react hooks ;)

all right guys, even if i didn't' received any help so far, i fixed the problem, i share here for everyone who got my problem. Hope will be helpful.

For some reason i don t really know, new Audio(src) is not a viable option in React, somehow the play() function as pause() and others are not working. So if like me you find yourself in the same situation, please make a component with the <audio> element in the render instead.

<audio id="audio">
 <source src={src} type="audio/mp3" />
</audio>

you can play ( or pause etc..) it using :

document.getElementById("audio").play();

so here the react component i create to play a sound once you hover on the elements of your choice, just pass an array of their css selectors in the props:

import React, { Component } from "react";

import soundfile from "../../internalAsset/sounds/button-1.mp3";

class ButtonAudioPlayer extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  componentDidMount() {
    // we add the even listener to buttons

    this.props.buttonsSelectors.forEach(selector => {
      var button1 = document.querySelector(selector);
      button1.addEventListener("mouseenter", () => {
        this.sound("play");
      });
      button1.addEventListener("mouseleave", () => {
        this.sound("stop");
      });
    });
  }

  sound = value => {
    const track = document.getElementById("audio");
    if (value === "play") {
      track.load();
      track.play();
    } else {
      track.pause();
    }
  };

  render() {
    return (
      <audio id="audio">
        <source src={soundfile} type="audio/mp3" />
      </audio>
    );
  }
}
export default ButtonAudioPlayer;

Hope you find this helpful :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM