Reputation: 341
setTimeout(() => this.setState({ messageSent: true }), 2000);
In the state initially messageSent: false
, and I just want this text to appear for 2 seconds. Instead, what it does is completely the opposite: it appears after 2 seconds (and forever). Why?
{this.state.messageSent ? (
<span className="message-sent">
Your message has been sent. We will get back to you soon. Thank you for contacting us!
</span>
) : null}
Upvotes: 0
Views: 3283
Reputation: 21
Your code won't work because the setState is being called after the timeOut.
Here is the logic that you after:
setState(messageSent) -> true
wait 2000ms
setState(messageSent) -> false
You can add a call back at the end of your setState as follow:
this.setState({ messageSent: true }, () => {
setTimeout(() => this.setState({ messageSent: false }), 2000);
});
Has been answered by: https://stackoverflow.com/a/61658196/5653540
I just added a little bit of explanation. (new users can't add an extra comment) =(
Upvotes: 1
Reputation: 8125
You need to work with state, Like loading
for first time would be null
. On submit, it will be true/loading
. Once loaded, need to be false.
Or you can create a component like Toast
and based on data you can play.
function Toast({open, message, autoClose, type = "info", timeout = 2000}) {
const [status, setStatus] = useState(open);
useEffect(() => {
if(autoClose) {
setTimeout(() => {
setStatus(false);
}, timeout);
}
}, []);
return (
<div>
{status ? (
<span className={"message-sent" + " " +type}>
{message}
</span>
) : null}
</div>
)
}
See below example:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style>
.error {
background-color: red;
}
.info {
background-color: blue;
}
</style>
</head>
<body>
<div id="root">Test</div>
<script type="text/babel">
const { createElement, useState, useEffect, useRef } = React;
function Toast({open, message, autoClose, type = "info", timeout = 2000}) {
const [status, setStatus] = useState(open);
useEffect(() => {
if(autoClose) {
setTimeout(() => {
setStatus(false);
}, timeout);
}
}, []);
return (
<div>
{status ? (
<span className={"message-sent" + " " +type}>
{message}
</span>
) : null}
</div>
)
}
function Loader() {
const [status, setStatus] = useState(null);
useEffect(() => {
setTimeout(() => {
setStatus(false);
}, 2000);
}, [status]);
const onSubmit = () => {
setStatus(true);
};
return (
<div>
{status === true ? (
<span className="message-sent">
Your message has been sent. We will get back to you soon. Thank you
for contacting us!
</span>
) : null}
<button onClick={onSubmit}>Click here to see message</button>
</div>
);
}
ReactDOM.render(<div>
<Loader />
<Toast open message={"Auto close message"} autoClose type="error" />
<Toast open message={"info message"} autoClose timeout={4000}/>
</div>, document.getElementById("root"));
</script>
</body>
</html>
Upvotes: 0
Reputation: 6735
The below is easiest solution by using &&
!this.state.showSentMessage && (
<span className="message-sent">
Your message has been sent. We will get back to you soon. Thank you for contacting us!
</span>
)
Upvotes: 0
Reputation: 2319
Try this:
this.setState({ showSentMessage: true }, () => {
setTimeout(() => this.setState({ showSentMessage: false }), 2000);
})
rendeer Code
{
this.state.showSentMessage ? (
<span className="message-sent">
Your message has been sent. We will get back to you soon. Thank you for contacting us!
</span>
) : null
}
Upvotes: 2
Reputation: 1
Reverse it and it should appear immediately and then hide after 2 seconds because of the timeout
!this.state.messageSent ? (
<span className="message-sent">
Your message has been sent. We will get back to you soon. Thank you for contacting us!
</span>
) : null}
Upvotes: 0
Reputation: 370689
You need to invert the logic - currently, since you're setting messageSent
to true
after 2000ms, this.state.messageSent ? ( jsx ) : null
enters the jsx
branch after 2000ms.
It'll probably be clearer if you change the property to something like showSentMessage
, which starts out true
, then set it to false
after 2000ms:
setTimeout(() => this.setState({ showSentMessage: false }), 2000);
{this.state.showSentMessage? (
<span className="message-sent">
Your message has been sent. We will get back to you soon. Thank you for contacting us!
</span>
) : null}
Upvotes: 0