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.