I want to render a snackbar ponent when clicking on the save button, by setting a showSnackbar state to true and do a simple conditional test in the main render method. React 101, no biggie. This snackbar ponent autohides after 2s.
The problem is that I want this state to reset back to false so the user is able to click the save button again and have the snackbar ponent to render again, since I want him to stay on the same form. I have tried a number of techniques but failed miserably. Here's the code I am using... perhaps there's a trivial way which I am missing:
class MyForm extends Component {
state = {
showSnackbar: false
};
..
saveChanges = async () => {
// this technique actually toggles the states in sequence successfully
// but I guess since it's super fast, React is not able to render the
// snackbar
await this.renderSnackbar();
await this.unrenderSnackbar();
};
renderSnackbar = async () => {
console.log("render"); // This is being displayed in console
await this.setState({ showSnackbar: true });
};
unrenderSnackbar = async () => {
console.log("unrender"); // This is being displayed in console
await this.setState({ showSnackbar: false });
};
..
..
render() {
return (
..
{this.state.showSnackbar && (
<MessageSnackbar message="Saved successfully!" />
)}
..
)
}
}
I want to render a snackbar ponent when clicking on the save button, by setting a showSnackbar state to true and do a simple conditional test in the main render method. React 101, no biggie. This snackbar ponent autohides after 2s.
The problem is that I want this state to reset back to false so the user is able to click the save button again and have the snackbar ponent to render again, since I want him to stay on the same form. I have tried a number of techniques but failed miserably. Here's the code I am using... perhaps there's a trivial way which I am missing:
class MyForm extends Component {
state = {
showSnackbar: false
};
..
saveChanges = async () => {
// this technique actually toggles the states in sequence successfully
// but I guess since it's super fast, React is not able to render the
// snackbar
await this.renderSnackbar();
await this.unrenderSnackbar();
};
renderSnackbar = async () => {
console.log("render"); // This is being displayed in console
await this.setState({ showSnackbar: true });
};
unrenderSnackbar = async () => {
console.log("unrender"); // This is being displayed in console
await this.setState({ showSnackbar: false });
};
..
..
render() {
return (
..
{this.state.showSnackbar && (
<MessageSnackbar message="Saved successfully!" />
)}
..
)
}
}
Share
Improve this question
asked Dec 10, 2018 at 8:34
JamesJames
3,81512 gold badges45 silver badges76 bronze badges
2
- 1 Why are you using async/await for this? – AnonymousSB Commented Dec 10, 2018 at 8:39
- you're right, that was a typo before I used a helper function.. – James Commented Dec 10, 2018 at 8:44
3 Answers
Reset to default 5Use 'setState' with callback function which can revert the state.
class MyForm extends Component {
state = {
showSnackbar: false,
message: ''
};
saveChanges = () => {
..
this.setState({ showSnackbar: true, message: 'Saved successfully' }, () => {
setTimeout(() => { this.setState({ showSnackbar: false }) }, 2000);
})
};
render() {
const { showSnackbar, message } = this.state;
return (
{ showSnackbar && (
<MessageSnackbar message />
)}
..
)
}
}
React doesn't implement DOM changes; it waits sometimes. So, when it sees change of state
from one value to another and immediate change back, it doesn't touch DOM obviously.
Use setTimeout
and you'll see the difference:
this.renderSnackbar();
setTimeout(() => { this.unrenderSnackbar(); }, 2000);
Another thing. this.setState
doesn't return promise, if you want to run some code only after change is applied to DOM, pass callback function:
this.setState(newState, callbackFunction)
Well, if I understood you correctrly, then there is two quick workarounds.
If MessageSnackbar
ponent is your own, then you can add some prop (e.g. onMount
, pass to this prop some function in which you will do this.setState({ showSnackbar: false }
, and then call this.props.onMount()
in MessageSnackbar
's ponentDidMount
.
Otherwise, you can use ponentDidUpdate
:
ponentDidUpdate(prevProps, prevState) {
if (this.state.showSnackbar && !prevState.showSnackbar) {
this.setState({ showSnackbar: false })
}
}