Reputation: 962
I'm using setTimeout()
(I even tried driftless too) to change buttons from disabled = true
to disabled = false
3 seconds after appearing on the DOM (onLoad=
). The buttons appear in sequence, after the previous button has been clicked.
The problem is, the setTimeout()
goes absolutely haywire: Each button's disabled = true
duration is seemingly sporadic (at least on Windows Chrome on 2 different PC's). Sometimes the button seemingly waits the full 3 seconds to enable, sometimes it enables instantaneously, and everything in-between.
What is causing this inconsistency, and how can I get each button to enable exactly 3 seconds (well, within a couple hundred milliseconds...not a big deal) after appearing?
Javascript
import React from 'react'
import ReactDOM from 'react-dom'
export default class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = { is_button_disabled: true, show_button_1: true, show_button_2: false, show_button_3: false, show_button_4: false };
}
handleDisableButton = (event) => {
setTimeout(() => this.setState({ is_button_disabled: false }), 3000);
}
handleShowButton = (buttonId) => {
if (buttonId === 'button_1'){
this.setState({ is_button_disabled: true})
this.setState({ show_button_1: false, show_button_2: true})
}
if (buttonId === 'button_2'){
this.setState({ is_button_disabled: true})
this.setState({ show_button_2: false, show_button_3: true})
}
if (buttonId === 'button_3'){
this.setState({ is_button_disabled: true})
this.setState({ show_button_3: false, show_button_4: true})
}
if (buttonId === 'button_4'){
this.setState({ is_button_disabled: true})
this.setState({ show_button_4: false, show_button_1: true})
}
}
render() {
const { show_button_1, show_button_2, show_button_3, show_button_4 } = this.state;
return (
<div butttons>
{show_button_1 &&
<button onLoad={this.handleDisableButton()} onClick={() => this.handleShowButton('button_1')} disabled={this.state.is_button_disabled}>Button1</button>
}
{show_button_2 &&
<button onLoad={this.handleDisableButton()} onClick={() => this.handleShowButton('button_2')} disabled={this.state.is_button_disabled}>Button2</button>
}
{show_button_3 &&
<button onLoad={this.handleDisableButton()} onClick={() => this.handleShowButton('button_3')} disabled={this.state.is_button_disabled}>Button3</button>
}
{show_button_4 &&
<button onLoad={this.handleDisableButton()} onClick={() => this.handleShowButton('button_4')} disabled={this.state.is_button_disabled}>Button4</button>
}
</div>
)
}
}
ReactDOM.render(<MyForm />, document.getElementById('root'));
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
</body>
</html>
Upvotes: 1
Views: 124
Reputation: 1195
You should fix this first.
<button id="myButton" onLoad={this.handleDisableButton} onClick={() => this.handleShowButton('button_1')} disabled={this.state.is_button_disabled}>Button1</button>
which means
this.handleDisableButton()
to
this.handleDisableButton
And clearTimeout
to prevent memory leak
I have fixed your sandboxcode:
componentDidMount() {
this.timeoutHandler = setTimeout(() => {
clearTimeout(this.timeoutHandler);
this.setState({ is_button_disabled: false });
}, 3000);
}
handleShowButton = (buttonId) => {
let newState = {};
if (buttonId === "button_1") {
newState = {
is_button_disabled: true,
show_button_1: false,
show_button_2: true
};
}
if (buttonId === "button_2") {
newState = {
is_button_disabled: true,
show_button_2: false,
show_button_3: true
};
}
if (buttonId === "button_3") {
newState = {
is_button_disabled: true,
show_button_3: false,
show_button_4: true
};
}
if (buttonId === "button_4") {
newState = {
is_button_disabled: true,
show_button_4: false,
show_button_1: true
};
}
this.setState(newState, () => {
this.timeoutHandler = setTimeout(() => {
clearTimeout(this.timeoutHandler);
this.setState({ is_button_disabled: false });
}, 3000);
});
};
componentWillUnmount() {
clearTimeout(this.timeoutHandler);
}
Upvotes: 3
Reputation: 439
There is no onLoad
event for buttons, which is why the method is never getting called if you pass it in by reference and only gets called when invoked directly.
You should call handleDisableButton()
as a callback to setState()
in your onClick
method, ie:
if (buttonId === "button_1") {
this.setState({
is_button_disabled: true,
show_button_1: false,
show_button_2: true
}, () => {
handleDisableButton();
);
}
This ensures that the timeout will start only once the state has been updated, and the timeout callback should consistently be called after 3 seconds.
Upvotes: 0
Reputation: 303
While using setState, can you try
this.setState({ ...this.state, is_button_disabled: true}) this.setState({ ...this.state, show_button_4: false, show_button_1: true})
Upvotes: 0