Skip to content

Conversation

@mgh
Copy link
Contributor

@mgh mgh commented Oct 13, 2016

Fixes #17.

Changes proposed:

  • wait before unmounting the portal if closeTimeoutMS is set
  • full details in commit message

Upgrade Path (for changed or removed APIs):

  • The upgrade path is to undo any workarounds or hacks (e.g. manually triggering the close animation before unmounting the Modal), though due to the lack of activity on the referenced issue, I'm guessing most users won't be affected?

Acceptance Checklist:

  • All commits have been squashed to one.
  • The commit message follows the guidelines in CONTRIBUTING.md.
  • Documentation (README.md) and examples have been updated as needed.
  • If this is a code change, a spec testing the functionality has been added.
  • If the commit message has [changed] or [removed], there is an upgrade path above.


shouldBeClosed: function() {
return !this.props.isOpen && !this.state.beforeClose;
return !this.state.isOpen && !this.state.beforeClose;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the Modal is unmounting, it won't have a chance to update the isOpen prop to false; however, the internal setState call will update state.isOpen correctly.

@claydiffrient
Copy link
Contributor

@mgh This looks good from a code perspective, but it'd be great to have a spec in place. I think we could do an async spec that verified that the time the callback is called is within some small margin of error from the timeout value specified.

@mgh mgh force-pushed the master branch 7 times, most recently from a7bca07 to a3e079c Compare February 6, 2017 12:56
@coveralls
Copy link

Coverage Status

Coverage increased (+0.7%) to 77.739% when pulling a3e079c on mgh:master into 6ba1c8d on reactjs:master.

@mgh
Copy link
Contributor Author

mgh commented Feb 6, 2017

@claydiffrient sounds good. I've updated the test specs to include an async spec as you proposed. The new test queries the DOM after the modal is unmounted to ensure the portal still exists until the closeTimeoutMS expires, so I had to update the other tests to ensure other modals weren't still lying around. (I noticed a related test for closeTimeoutMS that was commented out because it didn't work, so I fixed that as well.)

@diasbruno
Copy link
Collaborator

@mgh awesome! Is this action cancelable? (Just a question).

@mgh
Copy link
Contributor Author

mgh commented Feb 7, 2017

@diasbruno depends on what you mean by cancelable =) the original behavior of closing and then immediately reopening a modal should be unaffected (the first close is canceled and the portal is preserved). Unmounting then remounting the same Modal will not preserve the same portal though, as React instantiates a new Modal instance for each mount and each instance has its own portal. That behavior, though, is the same before and after this commit.

Copy link
Collaborator

@diasbruno diasbruno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rebase. 👍

Copy link
Collaborator

@diasbruno diasbruno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought If I approve this I could rebase from the interface. :)

@mgh
Copy link
Contributor Author

mgh commented Feb 18, 2017

@diasbruno I rebased. Two things to note:

  1. Original change (ebec638#diff-9e8d9aa8af75942f5423a4b030c5b78aR145):

    this.setState({
       ...                                                   
    }, this.afterClose);          →        }, () => this.afterClose());
    

    However, this same commit redefined afterClose:

    afterClose = () => {
    

    So I kept the original }, this.afterClose) since the extra function wrapper does not appear necessary.

  2. A new test did not unmount the modal, breaking my test which expects no modals to be left-over from previous tests. This same problem may affect tests in the future, and it's hard to debug since adding a new test can break my (unrelated) test. Thus, in addition to fixing the test in question, I also added:

    afterEach('check if test cleaned up rendered modals', () => { ... });
    

    which will now correctly identify tests that don't clean up:

    ...
    ✔ give back focus to previous element or modal.
    ✖ "after each" hook: check if test cleaned up rendered modals for "give back focus to previous element or modal."
    
    Finished in 1.446 secs / 0.072 secs
    
    SUMMARY:
    ✔ 11 tests completed
    ℹ 2 tests skipped
    ✖ 1 test failed
    
    FAILED TESTS:
      Modal
        ✖ "after each" hook: check if test cleaned up rendered modals for "give back focus to previous element or modal."
    

    Arguably, the afterEach hook could try automatically unmounting all modals first to make test writing easier.

Fixes issue reactjs#17: "When the modal is unmounted, it will abruptly close,
not waiting for any animations to finish."

The bug was caused by the Modal component unmounting the portal
immediately in `componentWillUnmount` regardless of whether the portal
is currently closing or would animate to close.

Now when a Modal has a non-zero `closeTimeoutMS`, the Modal inspects the
portal state before closing.  If the portal is open or closing, but not
closed, it waits to unmount the portal.  If the portal is open and not
already closing, the Modal calls closeWithTimeout() to trigger the
close.

Adds test to ensure portal DOM persists after Modal is unmounted when
the Modal has a `closeTimeoutMS` set.  Updates existing tests to
properly unmount test Modal instances.
@coveralls
Copy link

Coverage Status

Coverage increased (+0.2%) to 80.702% when pulling ac01dda on mgh:master into ebec638 on reactjs:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.5%) to 81.053% when pulling 34927f1 on mgh:master into ebec638 on reactjs:master.

@diasbruno
Copy link
Collaborator

Yeah, I've added this wrapper on afterClose (my bad) and forgot to remove. I add this because It was not firing cause it was a class method and not instance method or something.

Really like the afterEach, it is the best place to do some clean up for the next test. I believe we should add a function to force unmount any remain modal after a test.

@diasbruno diasbruno added the bug label Feb 18, 2017
@diasbruno diasbruno merged commit ba2fe90 into reactjs:master Feb 18, 2017
@diasbruno
Copy link
Collaborator

Tested and working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unmounting and animation

4 participants