Reputation: 296
I have a component called flash that is intended to be in the DOM only for 5 seconds (it's a message informing the user that he has sent the post successfully) and I want it to start fading away after 2 seconds, so that after 5 seconds when it's removed from the DOM it already has visibility set to 0. To achieve this, in the parent component I setTimeout() and send a prop containing a boolean set to true to the flash component, where it has an if waiting for that boolean and when it gets it, it assigns a new class to that component to make it fade away. It all sounds perfect, but unfortunately it doesn't work at all... I tried updating the class within the flash component but it also doesn't work... Maybe you can come up with something? I'm sure that sending flash messages in react with pre-arranged components is a trifle in React, but I just can't think of any way of doing it!
Parent component:
if(this.state.flashMessage){
flash = <Flash>{this.state.flashMessage}</Flash>
setTimeout(() => {
//here I send the component the prop 'close' after two seconds
flash = <Flash close>{this.state.flashMessage}</Flash>
}, 2000);
}
return (
<React.Fragment>
<div className={classes.postContainer}>
{posts}
<div className={classes.Card} onClick={this.showPostAdd}>
<img alt="add a post" src={addPostImage} />
</div>
</div>
{addPostActive}
{flash}
</React.Fragment>
);```
Here is the flash component
``` const flash = (props) => {
let classNames = [classes.Flash];
if(props.close){
classNames.push(classes.TestFlash);
}
return (
<div className={classNames.join(' ')}>
<p>{props.children}</p>
</div>
);
}
Upvotes: 1
Views: 1245
Reputation: 353
The render only runs when updating the component, and a setTimeout won't trigger that update. However, changing a state value does trigger the update for the component.
What you should do is print the Flash component directly on the render method and bind the close prop to a state boolean.
<Flash close={this.state.closeFlashMessage}>{this.state.flashMessage}</Flash>
And I'd put the timeout function on the componentDidMount() method.
componentDidMount() {
this.mounted = true;
setTimeout(() => {
//check the mounted state in case the component is disposed before the timeout.
if(this.mounted) {
//here I send the component the prop 'close' after two seconds
this.setState({ closeFlashMessage: true });
}
}, 2000);
}
//add this method to prevent any state management during the component's disposal
componentWillUnmount() {
this.mounted = false;
}
Upvotes: 1
Reputation: 119
This does not work because simply setting flash = ...
will not trigger a re-render. You will need to store that information in your component's state and update it there in order to make it work correctly. I think something like this would work:
{this.state.flashMessage && <Flash close={this.state.isFlashMessageClosed}>{this.state.flashMessage}</Flash>
I would also not recommend setting a timeout directly in your render method. This should be a side effect triggered by a state change so I would recommend putting it in componentDidUpdate
like so:
componentDidUpdate(prevProps, prevState) {
if(prevState.flashMessage !== this.state.flashMessage) {
// If the flash message changed, update state to show the message
this.setState({ isFlashMessageClosed: false });
setTimeout(()=>{
// Update state to close the message after 2 seconds
this.setState({ isFlashMessageClosed: true });
}, 2000);
}
}
Hopefully that will work for you.
Upvotes: 1