4

I want to create a Modal-like component that receives an open/closed boolean as a prop, then stores that value in the component state. When closing the Modal, I want to update the close boolean prop, but wait a few seconds before updating the component state so that I can add transition classes and animate the exit.

With componentWillReceiveProps, I could accomplish this by wrapping this.setState in a timeout and add the classes in the meantime. With the new React 16.3 API, I see that is is recommended to use the getDerivedStateFromProps instead.

Since getDerivedStateFromProps "should return an object to update state, or null to indicate that the new props do not require any state updates," (React docs) I want the method to look something like this:

static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.menuIsOpen === false && prevState.menuIsOpen === true) {
        return setTimeout(() => { menuIsOpen: false}, 1000);
    }
    return null;
}

But that doesn't work. I've read that setTimeout does not return a value but am wondering if there is a more elegant solution to the problem than returning a promise.

SeanMcP
  • 293
  • 6
  • 19

1 Answers1

10

You can use componentDidUpdate:

componentDidUpdate(prevProps){
    // update your class names...
    if (!this.props.menuIsOpen && this.state.menuIsOpen) {
        setTimeout(() => this.setState({ menuIsOpen: false}), 1000);
    }
}
Tomasz Mularczyk
  • 34,501
  • 19
  • 112
  • 166
  • 4
    This is correct. You'll also want to think about what should happen if modal is opened and closed and opened again in quick succession, as you may have race conditions unless you're also tracking something like `isAnimating` in state and are careful to reset it / cancel timeouts when necessary. Once you get it working, I would probably suggest extracting the transition logic into a separate `` component with a [render prop API](https://reactjs.org/docs/render-props.html) so that you can reuse it. – Dan Abramov May 01 '18 at 12:09
  • I would add that there is a risk that setState may get called on unmounted component throwing an error as setTimeout is asynchronous. – Tomasz Mularczyk May 01 '18 at 14:03