Looping Audio with React.js - reactjs

I think this is a rather simple question, but I am trying to self-learn React.js and am a bit confused about how audio loops. I understand looping when rendering and returning plain html audio tags, but I am not sure how to do it without. So far I have learned how to toggle play and pause buttons thanks to another StackOverflow question I found, but am not sure how to make the audio loop as well. I would like to keep the current code if possible (I tried to use the audio tags mentioned above instead when rendering, but it was hard to re-incorporate the image toggling again) and just learn how to incorporate looping into it. Any help or resources would be much appreciated! Below is the code I have reduced it to so far:
export class PlaySound extends Component {
constructor(props) {
super(props);
this.state = {
play: true
};
this.url = "https://actions.google.com/sounds/v1/water/waves_crashing_on_rock_beach.ogg";
this.audio = new Audio(this.url);
this.togglePlay = this.togglePlay.bind(this);
}
togglePlay() {
this.setState({
play: !this.state.play
});
this.state.play ? this.audio.play() : this.audio.pause();
}
render() {
return (
<div>
<button
id="audioBtn"
onClick={this.togglePlay}> {this.state.play ? <PlayArrow /> : <Pause />}
</button>
</div>
);
}
}

you can just set loop = true
togglePlay() {
this.setState({
play: !this.state.play
});
this.state.play ? this.audio.play() : this.audio.pause();
this.audio.loop = true;
}

You can add an ended listener to your Audio object in which you set the time back to 0 and start playing it again.
class PlaySound extends Component {
constructor(props) {
super(props);
this.state = {
play: true
};
this.url = "https://actions.google.com/sounds/v1/water/waves_crashing_on_rock_beach.ogg";
this.audio = new Audio(this.url);
this.audio.addEventListener('ended', function () {
this.currentTime = 0;
this.play();
}, false);
this.togglePlay = this.togglePlay.bind(this);
}
// ...
}
class PlaySound extends React.Component {
constructor(props) {
super(props);
this.state = {
play: false
};
this.url = "https://actions.google.com/sounds/v1/water/air_woosh_underwater.ogg";
this.audio = new Audio(this.url);
this.audio.addEventListener('ended', function () {
this.currentTime = 0;
this.play();
}, false);
this.togglePlay = this.togglePlay.bind(this);
}
togglePlay() {
const wasPlaying = this.state.play;
this.setState({
play: !wasPlaying
});
if (wasPlaying) {
this.audio.pause();
} else {
this.audio.play()
}
}
render() {
return (
<div>
<button
id="audioBtn"
onClick={this.togglePlay}> {this.state.play ? "Pause" : "Play"}
</button>
</div>
);
}
}
ReactDOM.render(<PlaySound />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Related

React Hooks in class using timeout

I am quite new in React... I have page where window is showing with little delay..
it is made with Hooks:
export default function LoginPage() {
const [cardAnimaton, setCardAnimation] = React.useState('cardHidden');
setTimeout(function() {
setCardAnimation('');
}, 700);
<form>
<Card login className={classes[cardAnimaton]}>
Now I want to use classes in that page and I want to preserve the same effect..
So I am trying something like:
export default class LoginPage extends React.Component {
constructor(props) {
super(props);
this.state = {
cardHidden: true,
};
}
componentDidMount() {
this.timeout = setTimeout(() => {
this.setCardAnimation('');
}, 700);
}
setCardAnimation = () => {
this.cardAnimaton({ cardHidden: false });
};
I have no idea... got stuck there...
You just need to set your cardHidden: false inside componentDidMount and then you can add animation based on cardHidden state.
here is a working Demo which I used cardHidden state to show or hide different text on screen which you can use this method for adding different animation.
just click Run code snippet to see how it works
class LoginPage extends React.Component {
constructor(props) {
super(props);
this.state = {
cardHidden: true,
};
}
componentDidMount() {
this.timeout = setTimeout(() => {
this.setState({
cardHidden: false
});
}, 700);
}
render() {
if(this.state.cardHidden){
return <div>I'm Hidden</div>
} else {
return <div>Haha, I'm Visible</div>
}
}
}
const rootDiv = document.getElementById('root');
ReactDOM.render(<LoginPage />, rootDiv);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
In class-based component, you need to use this.setState to update the state.
export default class LoginPage extends React.Component {
constructor(props) {
super(props);
this.state = {
cardHidden: true,
};
}
componentDidMount() {
this.timeout = setTimeout(() => {
this.setState({ cardHidden: false });
}, 700);
}
...
check https://reactjs.org/docs/react-component.html#setstate

How to generate random numbers where user refresh the page in react

Hi I am creating a chat bot using react.My code is:
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
random : '',
}
}
componentDidMount(){
addResponseMessage('Welcome to React Bot! Type start');
return this.setState({random : Math.floor(Math.random()*10000)});
}
handleNewUserMessage = (newMessage) => {
fetch('http://localhost:5005/webhooks/rest/webhook', {
method: 'POST',
headers : new Headers(),
body:JSON.stringify({"sender":this.state.random, "message": newMessage}),
}).then((res) => res.json())
.then((data) => {
var first = data[0];
var mm= first.text;
var i;
console.log(mm)
toggleMsgLoader();
setTimeout(() => {
toggleMsgLoader();
if (data.length < 1) {
addResponseMessage("I could not get....");
}
else{
addResponceMessage(mm)
}
}
}
handleQuickButtonClicked = (e) => {
addUserMessage(e);
this.handleNewUserMessage(e);
setQuickButtons([]);
}
render() {
return (
<Widget
title="Rasa Sample Bot"
subtitle="Asistente virtual"
senderPlaceHolder="Type here ..."
handleNewUserMessage={this.handleNewUserMessage}
handleQuickButtonClicked={this.handleQuickButtonClicked}
badge={1}
/>
);
}
}
When user give to messages to my bot.It will call handleNewUsermMessage() and execute and give responses to user. body:JSON.stringify({"sender":this.state.random, "message": newMessage}), this code for when user refreshing the page that sender id will be change. But here every message it will create a random Id. I don't want every message. Whenever user refresh the page then only i want create random id.
How to solve this. Please help. Thanks in advance
Define in your state
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
random: Math.floor(Math.random()*100),
}
}
handleClick = () => {
this.setState({random: this.min + (Math.random() * (this.max - this.min))});
};
render() {
return (
<div>
<button onClick={this.handleClick}>Click me</button>
{this.state.random}
</div>
);
}
}
try this write in componentDidMount.
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
random : '',
}
}
componentDidMount() {
this.setState({random : Math.floor(Math.random()*100)});
}
handleClick = () => {
this.setState({random: this.min + (Math.random() * (this.max - this.min))});
};
render() {
return (
<div>
<button onClick={this.handleClick}>Click me</button>
{this.state.random}
</div>
);
}
}
In react when you refresh the browser the components remounts. So to generate random number on refresh you should call the random number generating function in componentDidMount() lifecycle method. The below code will work.
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
random: null,
}
}
min = 1;
max = 100;
generateRandom =()=>{
this.setState({random: this.min + (Math.random() * (this.max
this.min))
}});
componentDidMount(){
this.generateRandom();
}
handleClick = () => {
this.generateRandom();
};
render() {
return (
<div>
<button onClick={this.handleClick}>Click me</button>
{this.state.random}
</div>
);
}
}
this.state = {
random: Math.floor(Math.random()*100)
}
Just Update the above line in the constructor and it will all work just fine

setState inside constructor not working properly: ReactJS

I'm trying to run the below code in React+Redux but am running into an unhandled
exception 'NodeInvocationException: Cannot read property 'showText' of
null TypeError: Cannot read property 'showText' of null'
import * as React from 'react';
import { NavMenu } from './NavMenu';
import { Component } from 'react';
export interface BlinkState
{
showText: boolean;
text: '';
}
type BlinkProps = BlinkState;
class Blink extends React.Component<BlinkProps, BlinkState> {
constructor(props: BlinkProps) {
super(props);
//this.state = { showText: true };
this.setState({ showText: true, text: props.text });
// Toggle the state every second
setInterval(() => {
this.setState(previousState => {
return { showText: !previousState.showText };
});
}, 1000);
}
render() {
let display = this.state.showText ? this.props.text : ' ';
return <div>{ display }</div>;
}
}
export class Layout extends React.Component<{}, {}> {
public render() {
return <div className='container-fluid'>
<Blink showText=false text='I love to blink' />
</div>;
}
}
I'm just trying to figure out how to render the Blink copmonent with the props passed in...
You missed the basic thing, use of constructor and setState, use of constructor is to initialize the state value and use of setState is to update the state value, so using setState inside `constructor doesn't makes any sense.
Better way will be, initialise the state in constructor and to run the time use componentDidMount lifecycle method, also don't forgot to stop the time before unmounting the component, to clear it use componentWillUnmount lifecycle method.
Write the component like this:
class Blink extends React.Component<BlinkProps, BlinkState> {
constructor(props: BlinkProps) {
super(props);
this.state = { showText: false };
}
componentDidMount(){
this.timer = setInterval(() => {
this.setState(previousState => {
return { showText: !previousState.showText };
});
}, 1000);
}
componentWillUnmount(){
clearInterval(this.timer)
}
render() {
let display = this.state.showText ? this.props.text : ' ';
return <div>{ display }</div>;
}
}
Working code:
class Blink extends React.Component {
constructor(props) {
super(props);
this.state = { showText: true, text: props.text };
}
componentDidMount(){
this.timer = setInterval(() => {
this.setState(prev => {
return { showText: !prev.showText };
});
}, 1000);
}
componentWillUnmount(){
clearTimer(this.timer)
}
render() {
let display = this.state.showText ? this.props.text : ' ';
return <div>Hello { display }</div>;
}
}
class Layout extends React.Component{
render() {
return <div className='container-fluid'>
<Blink text='I love to blink' />
</div>;
}
}
ReactDOM.render(<Layout/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'/>
You should not specify actions to be taken in the constructor or use setState there, constructor should be used to simply set an initial state.
Also you might need to update the state text since its being set based on props. Do it in the componentWillReceiveProps.
Also when you are using setInterval, make sure to clearInterval when the componentUnmounts
constructor(props: BlinkProps) {
super(props);
this.state = { showText: true, text: props.text };
}
componentWillReceiveProps(nextProps) {
this.setState({text: nextProps.text});
}
componentDidMount() {
// Toggle the state every second
this.interval = setInterval(() => {
this.setState(previousState => {
return { showText: !previousState.showText };
});
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval)
}

blinking text with React using state and setTimeOut

I am trying to show blinking text using react:
class BlinkLable extends React.Component {
constructor(props) {
super(props);
this.state = {showlabel: true,
label: this.props.label
};
this.myFunction = this.myFunction.bind(this);
}
myFunction()
{
var sLb = ! (this.state.showlabel);
this.setState({showlabel: sLb});
}
componentDidMount() {
setTimeout(this.myFunction, 3000)
}
render() {
return (
<div>
{(this.state.showlabel)?this.state.label:''}
</div>
);
}
}
ReactDOM.render(
<BlinkLable label='MY MESSAGE'/>,
document.getElementById('labelId')
);
However, after it shows MY MESSAGE, this message dissapears and never comes back. What could be the problem?
You need to use setInterval() method.
componentDidMount() {
setInterval(this.myFunction, 3000)
}
More Info: 'setInterval' vs 'setTimeout'
Modify this function to:
myFunction()
{
this.setState((prevState) => {
return {
showlabel: !prevState.showLabel
}
});
}
class BlinkLable extends React.Component {
constructor(props) {
super(props);
this.state = {showlabel: true,
label: this.props.label
};
this.myFunction = this.myFunction.bind(this);
}
myFunction(){
var sLb = ! (this.state.showlabel);
this.setState({showlabel: sLb});
}
render(){
return (
<div>
{(this.state.showlabel)?this.state.label:''}
</div>
);
}
componentDidUpdate() {
setTimeout(this.myFunction, 2000)
}
componentDidMount(){
setTimeout(this.myFunction, 2000)
}
}
ReactDOM.render(
<BlinkLable label='MY MESSAGE'/>,
document.getElementById('labelId')
);
<div id="labelId"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
you need to know react's component life cycle.
componentDidMount() is called only when a component is mounted.
componentDidMount() is invoked immediately after a component is
mounted. Initialization that requires DOM nodes should go here.
Therefore if you want to keep blinking, add componentDidUpdate().

How to assign a prop value to a state in react

I have an overlay which is launched from another React component which have a button that also changes itself. The change happens when the user clicks the button, then the button changes it's classname. It also sends a prop value to the children component which is the overlay. The overlay adds a class depending on the property and if it is clicked. Everthing is working pretty nice, but now I have to do another thing. When a user click on the overlay, it have to close up. Before this change, everything was working for the button I mentioned earlier.
Well this is the button component:
export default class StatusBarButton extends React.Component {
constructor(props) {
super(props)
this.state = {active: false}
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.setState({ active: !this.state.active });
}
render() {
var cx = require('classnames');
var button = cx ({
'statusbar-button-container' : true,
'active' : this.state.active
});
var animation = cx ({
'statusbar-button-cross-image' : true,
'rotate' : true,
'active' : this.state.active
});
return (
<div className="astatusbar-center-wrapper">
<div className={button} onClick={this.handleClick}>
<img src="images/navbar-element-icon-cross.png" className={animation}/>
</div>
<OverlayView isOpen={this.state.active} />
</div>
);
}
}
And this is the Overlay at the moment:
export default class OverlayView extends React.Component {
constructor (props){
super(props);
this.state = {open: false}
this.setState({ open: this.props.isOpen });
}
render() {
var cx = require('classnames');
var overlay = cx({
'overlay': true,
'overlay-slidedown': true,
'open': this.state.open
});
return (
<div className={overlay} onClick={this._closeOverlay}>
<div className="overlay-menu-wrapper">
<OverlayNewInvoiceButton />
<OverlayNewBudgetButton />
<OverlayNewTicketButton />
</div>
</div>
);
}
}
As you see I'm trying to get the prop value and assign it to the state, but it's not working. How can I assign the prop value to the state and use it?
Regards,
JP
You are missing componentWillReceiveProps(props) method in your OverlayView component.
export default class OverlayView extends React.Component {
constructor (props){
super(props);
this.state = {open: props.isOpen}
}
componentWillReceiveProps(props) {
this.setState({open: props.isOpen});
}
render() {
let open = '';
if (this.state.open === true) {
open = 'open';
}
let overlayClass = `overlay overlay-slidedown ${open}`;
return (
<div className={overlayClass} onClick={this._closeOverlay}>
<div className="overlay-menu-wrapper">
<span>{open}</span>
</div>
</div>
);
}
}
Full working example:
https://codesandbox.io/s/35wLR4nA
constructor(props, context) {
super(props, context);
this.state = {
value: ''
};
}
componentWillReceiveProps(){ //this is called to before render method
this.setState({
value:this.props.data
})
You're problem might be that you are trying to fetch the class props with this. I think you are supposed to use the props passed into the constructor.
Like this:
constructor (props){
super(props);
this.state = {open: false}
this.setState({ open: props.isOpen });
}
Not sure why you aren't doing it in one line like this though: this.setState = { open: props.isOpen };
Finally i conserved the property which changes the class, is not bad that way. and i fixed with the help of this: Pass props to parent component in React.js and of course the help of a work mate. the end version is this:
This is the parent:
export default class StatusBarButtonView_Profit extends React.Component {
constructor(props) {
super(props)
this.state = {active: false}
this._openOverlay = this._openOverlay.bind(this)
this._closeOverlay = this._closeOverlay.bind(this)
}
_openOverlay() {
if (this.state.active == false) {
this.setState({ active: true });
console.log('boton lanza overlay');
} else {
this.setState({ active: false });
console.log('boton cierra overlay');
}
}
_closeOverlay(Overlay) {
if (this.state.active == true) {
this.setState({ active: false });
} else {
this.setState({ active: true });
}
}
render() {
var cx = require('classnames');
var button = cx ({
'aui-profit-statusbar-button-container' : true,
'active' : this.state.active
});
var animation = cx ({
'aui-profit-statusbar-button-cross-image' : true,
'rotate' : true,
'active' : this.state.active
});
return (
<div className="aui-profif-statusbar-center-wrapper">
<div className={button} onClick={this._openOverlay}>
<img src="images/aui-navbar-element-icon-cross.png" className={animation}/>
</div>
<OverlayView_Profit isOpen={this.state.active} onClick={this._closeOverlay}/>
</div>
);
}
}
this is the child:
export default class OverlayView_Profit extends React.Component {
constructor (props){
super(props);
}
_closeOverlay() {
this.props.onClick();
}
render() {
var cx = require('classnames');
var overlay = cx({
'aui-overlay': true,
'aui-overlay-slidedown': true,
'open': this.props.isOpen
});
return (
<div className={overlay} onClick={this._closeOverlay.bind(this)}>
<OverlayNewInvoiceButtonView_Profit />
<OverlayNewBudgetButtonView_Profit />
<OverlayNewTicketButtonView_Profit />
</div>
);
}
}
now everything works fine.

Resources