简体   繁体   中英

Reset State after Conditional Render of React Component

I want to render a snackbar component 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 component 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 component 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!" />
        )}
      ..
    )
  }

}

Use '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 component is your own, then you can add some prop (eg 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 componentDidMount .

Otherwise, you can use componentDidUpdate :

componentDidUpdate(prevProps, prevState) {
    if (this.state.showSnackbar && !prevState.showSnackbar) {
        this.setState({ showSnackbar: false })
    }
}

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM