Reputation: 815
I'm trying to build a horse race app and being new to react, I'm struggling with handling a click event when a user clicks the 'Start' button for the jockey to race. When I remove the handleClick
function (as commented out below), the jockey races (using react's progress bar) automatically when I reload the page. I only want that functionality when I click the 'Start' button.
App.js
import React, { Component } from 'react';
import Progress from 'react-progressbar';
import logo from '../../images/logo.svg';
import './App.css';
class Jockey extends Component {
state = {
interval: Math.floor(Math.random() * 500),
progress: 5,
}
// handleClick = () => {
// console.log('The link was clicked.');
componentDidMount = () => {
this.interval = setInterval(this.timer, this.state.interval);
}
timer = () => {
this.setState({ progress: this.state.progress + 1 });
// (this.state.progress >= 99) ? this.setState({ progress: 100 }) : "" ;
if(this.state.progress >= 99) {
this.setState({ progress: 100 })
};
}
// }
render() {
const Buttons = () => (
<div className="App-buttons">
<button className="ui primary button" onClick={this.handleClick}>Start</button>
<button className="ui button">Reset</button>
</div>
);
return (
<div>
<Buttons />
<div className="App-field">
<h1>Race Track</h1>
<img src="https://avatars1.githubusercontent.com/u/3757315?v=4" alt=""/>
<Progress className="App-progress" completed={this.state.progress}/>
</div>
</div>
);
}
}
export class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to the React Race Hustle</h1>
</header>
<Jockey />
</div>
);
}
}
Upvotes: 1
Views: 355
Reputation: 62773
With your code as is (with the handleClick
commented out), the componentDidMount()
function will automatically run when the component mounts. Which means the timer()
will begin running on the defined interval when the component mounts.
You'll want to make two changes:
timer()
into the handlercomponentDidMount()
function outside the handlerhandleClick = () => {
console.log('The link was clicked.');
this.interval = setInterval(this.timer, this.state.interval);
timer = () => {
this.setState((prevState) => ({ progress: (prevState.progress + 1 > 98 ? 100 : prevState.progress + 1) });
}
}
And we no longer need the componentDidMount()
function.
Upvotes: 3
Reputation: 28654
I tried to change your code so that it satisfied your needs; hope you can see kind of changes it needed.
import React from 'react';
import ReactDOM from 'react-dom';
import Hello from './Hello';
class Jockey extends React.Component {
constructor(props){
super(props);
this.state = {
interval: Math.floor(Math.random() * 500),
progress: 5,
}
this.handleClick=this.handleClick.bind(this);
}
handleClick (){
let that = this;
this.interval = setInterval(function () {
that.setState((ps)=>{
if(ps.progress + 1>=99) return {progress:100}
return {progress: ps.progress + 1 }}
);
}, this.state.interval);
}
render() {
const Buttons = () => (
<div className="App-buttons">
<button className="ui primary button" onClick={this.handleClick}>Start</button>
<button className="ui button">Reset</button>
</div>
);
return (
<div>
<Buttons />
<div className="App-field">
<h1>Race Track</h1>
<img src="https://avatars1.githubusercontent.com/u/3757315?v=4" alt="" />
<div className="App-progress" completed>{ this.state.progress }</div>
</div>
</div >
);
}
}
ReactDOM.render(
<Jockey />,
document.getElementById('root')
);
Some comments:
I used functional setState
too; because what you had is not the right way to set state when state depends on value from previous state.
You can also call clearInterval
when component unmounts.
And I have rendered the progress inside a div instead of a Progress component.
and I would not put interval
inside state; you normally don't put stuff in state if it is not used inside render.
Upvotes: 2