I have a React component called PopUpBanner
that I use to show messages. For example, in my login component, I use it like this. If an error occurs, then I set the bannerMessage
state to have text so that the banner shows:
this.setState({
bannerMessage: {
msg: error.message + ". Incorrect email address or password.",
isError: true,
},
});
Here is how the component is then used:
<PopUpBanner
message={bannerMessage.msg}
isError={bannerMessage.isError}
></PopUpBanner>
And here is the PopUpBanner
class:
import React, { Component } from "react";
class PopUpBanner extends Component {
constructor(props) {
super(props);
this.state = {
message: this.props.message,
};
}
// TODO : not in use
reset = () => {
this.resetId = setTimeout(
function () {
this.setState({ message: "" });
}.bind(this),
3000
);
};
componentDidMount() {}
componentWillUnmount() {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
console.log("clearing time out");
}
}
render() {
const message = this.props.message;
const isError = this.props.isError;
return (
<div style={message != "" ? { display: "block" } : { display: "none" }}>
<div>
{isError ? (
<div
className="alert alert-danger text-center"
role="alert"
style={{ width: "50%", margin: "auto" }}
>
{message}
</div>
) : (
<div
className="alert alert-primary text-center"
role="alert"
style={{ width: "50%", margin: "auto" }}
>
{message}
</div>
)}
</div>
</div>
);
}
}
export default PopUpBanner;
The problem is that the PopUpBanner
is shown until the page is refreshed or navigated to another page.
So if you look at the PopUpBanner
class, I attempted to use setTimeout
but wasn't able to finish it.
Any ideas on how I can transform PopUpBanner
component to be on a timer?
I see two options:
Handle it in the parent component, only rendering PopUpBanner
when it should be there, using setTimeout
to trigger a state update that re-renders the parent without rendering PopUpBanner
.
Handle it in PopUpBanner
, returning null
from render
after the expiration.
I would prefer #1 over #2. But your existing code is basically doing #2, you just have to adjust render
to support it:
render() {
const message = this.props.message;
if (!message) {
return null;
}
// ...show the message...
But as discussed in teh comments, I wouldn't copy props to state like that. So instead:
constructor(props) {
super(props);
this.state = {
expiredMessage: null,
};
}
then to expire a message:
setupExpiration() {
this.expirationTimer = setTimeout(() => {
this.setState(() => ({expiredMessage: this.props.message}));
}, 1000); // <== Or however long you want it showing
}
...which you call from a couple of lifecycle methods:
componentDidMount() {
this.setupExpiration();
}
componentDidUpdate() {
this.setupExpiration();
}
and render
becomes:
render() {
const { expiredMessage } = this.state;
const { message } = this.props;
if (expiredMessage === message) {
return null;
}
// ...show the message...
But again, I'd go for having the parent in control of this, actually removing PopUpBanner
when it shouldn't be showing:
class PopUpBanner extends React.Component { render() { const {message} = this.props; return <div className="banner">{message}</div>; } } class Parent extends React.Component { state = { message: null, }; constructor(props) { super(props); this.showMessage = this.showMessage.bind(this); this.messageTimer = 0; } showMessage() { clearTimeout(this.messageTimer); this.setState({message: "Hi there, I'm a banner"}); this.messageTimer = setTimeout(() => { this.setState({message: null}); }, 1000); } render() { const {message} = this.state; const {showMessage} = this; return <div className="with-banner"> {message && <PopUpBanner message={message} />} <div> <input type="button" value="Show Message" onClick={showMessage} /> </div> </div>; } }; ReactDOM.render(<Parent />, document.getElementById("root"));
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
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.