question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

<Dialog /> is not a controlled component

See original GitHub issue

Example:

import React, { Component } from 'react'
import { render } from 'react-dom'

import Dialog, {
  DialogContent,
} from '@material/react-dialog';

class AlwaysOpenedDialog extends Component {
  state = {
    open: true
  }

  render () {
    return (
      <Dialog
        open={this.state.open}
        onClose={() => {
          // I won't do anything in `onClose` so the dialog is expected to be always opened.

          // In a more normally case, I want to close the dialog conditionally
          // if (this.validate()) {
          //   this.setState({open: false})
          // } else {
          //   this.setState(null)
          // }
        }}
      >
        Hello World
      </Dialog>
    )
  }
}

render(<AlwaysOpenedDialog />, document.getElementById('root'))

When I click the mask, the dialog still closed.

According to the React docs, just like the native input element in React, <input type="text" value={this.state.value} onChange={this.handleChange} />, when you try to type something in the input element, this would trigger onChange event, but if you don’t change this.state.value in the onChange event handler, the value of this input element won’t changed, just like this input element is being locked.

In my opinion, the correct logic for Dialog component is that, when users try to close the dialog(via mouse click or keyboard), this would trigger onClose event, but finally the dialog is closed or not, is depending on the prop open, which respect React controlled components pattern.

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:3
  • Comments:18 (12 by maintainers)

github_iconTop GitHub Comments

1reaction
dawsonc623commented, Mar 30, 2019

@moog16 I have been running through the flow of how Dialogs are closed, and this is an interesting case. The challenge here is that there is no way to “cancel” a close; once the foundation object knows about the close interaction occurring, unless escapeKeyAction or scrimClickAction are set to empty strings the Dialog will close. There is not really anything the React component can do to stop it at that point. I can think of two solutions to this (if you can think of better ones feel free to share them):

  1. Have the React component adopt the logic contained in MDCDialogFoundation’s handleInteraction and handleDocumentKeydown methods. This solves the problem by allowing the React component control the exact conditions under which close is called. The major downside is the code duplication. I would like to avoid this solution if at all possible.

  2. Refactor the MDCDialogFoundation to allow the close process to be cancelled. Since there is the notifyClosing hook that is fired before any of the actual close logic begins, this could be done by either allowing notifyClosing to return false to cancel, or adding a cancelClose method which could be called from the notifyClosing hook. While semantically it seems weird that a controlled component would have to “cancel” a close versus preventing one from occurring at all, I do like this option - especially compared to the other.

I will keep looking at it and maybe fiddle around with what it would take to implement option 2 in case it helps think of something else that does not require code duplication or reaching into the foundation code (or to get a head start if option 2 is what we decide to go with).

As an aside, I had a little difficulty getting unit tests to run through the Windows Subsystem for Linux on Windows 10, but Karma can be configured to do it. I did not see any documentation related to this, so I am curious if we wanted to add documentation for getting that working (or even add a karma.wsl.conf file for developers using WSL).

1reaction
moog16commented, Mar 27, 2019

Ya - I think the only way we could do that is with a temporary prop…If we have that, people could slowly migrate over. Its not the best, but its the simplest thing I can think of. I also don’t want to break people that have been using this component, and they should be given ample time to upgrade. So let’s go with the temporary prop. Could you make sure to comment next to it and open an issue to remove it as well?

Read more comments on GitHub >

github_iconTop Results From Across the Web

jquery - Dialog is not a function - React
I think the problem is with the selector $('<div>').dialog({. try to inspect $('') from the developer tools. might be this should work
Read more >
krpeacock/react-controlled-dialog: A declarative interface ...
This component is designed to not be in control of its own status. It requires its parent to tell it when to open,...
Read more >
Uncontrolled Components
In a controlled component, form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by...
Read more >
ARIA: dialog role - Accessibility - MDN Web Docs - Mozilla
Dialogs can be modal or non-modal. When a modal dialog appears on the screen, it's not possible to interact with any page content...
Read more >
<af:dialog>
Dialog Events. Client Dialog Event · Using Input Components Inside a Dialog. When using input components, such as inputText , pressing the Cancel-button...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found