最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Reset State after Conditional Render of React Component - Stack Overflow

programmeradmin3浏览0评论

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
Add a ment  | 

3 Answers 3

Reset to default 5

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 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 })
    }
}
发布评论

评论列表(0)

  1. 暂无评论