Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modal does not work with React 16 #188

Closed
jochenberger opened this issue Jul 17, 2017 · 44 comments
Closed

Modal does not work with React 16 #188

jochenberger opened this issue Jul 17, 2017 · 44 comments

Comments

@jochenberger
Copy link
Contributor

Probably the same issue as facebook/react#9808.
When the Modal is shown and tries to get focus (via componentDidUpdate -> onShow - focus), setModalNode will not have been called and getDialogElement will return undefined.

@jochenberger jochenberger changed the title Modal does not work with React 16 Modal does not work with React 16 (alpha) Jul 17, 2017
@jochenberger
Copy link
Contributor Author

@jquense
Copy link
Member

jquense commented Jul 19, 2017

Fo v16 we'll want to switch to the new (YAH!) portal api

@jochenberger jochenberger changed the title Modal does not work with React 16 (alpha) Modal does not work with React 16 (beta) Jul 27, 2017
@billschaller
Copy link

billschaller commented Jul 31, 2017

Edit: I had a subpackage still referencing the older version of react-bootstrap. Latest is still broken with React 16 though :(

@jquense @jochenberger Current shipping version of react-bootstrap is still referencing react-overlay@0.7.0. That version is still using string refs, and that's not working in the Modal component for some reason with React 16.

Would you consider hotfixing this? Kind of a blocker :(

@jquense
Copy link
Member

jquense commented Jul 31, 2017

we can't hotfix RB to v0.8 because there are a few breaking changes, we need to do it on a major bump of RB

@billschaller
Copy link

Could you push an @next version to npm?

@jquense
Copy link
Member

jquense commented Jul 31, 2017

I'm not sure that would even help no version of RO uses the new portal api yet.

string refs should work still with the old API I would open an issue on the React repo since its a v16 bug

@billschaller
Copy link

Ah - Part of my app was on 30.10, and the string ref was still there.

The latest release is still broken in 16 though.

It looks like the child component of Portal passed in by Modal is not mounted by the time Modal.componentDidUpdate is called - this makes sense, as AFAIK that lifecycle callback doesn't fire until the commit phase. The proper thing to do is to have the child you pass to the Portal component kick off onShow instead of doing it from cDU or cDM in the Modal component itself.

@billschaller
Copy link

@jquense Sent you a chat request

@jquense
Copy link
Member

jquense commented Aug 1, 2017

@billschaller sorry just saw the request. You are better off pinging me in the react-bootstrap discord channel https://discord.gg/0ZcbPKXt5bXLs9XK i'm monasticpanic

@jochenberger jochenberger changed the title Modal does not work with React 16 (beta) Modal does not work with React 16 (beta/RC) Sep 12, 2017
@KagamiChan
Copy link

Is there any news on the landing of RO on RB? I'd like to help but I don't know what are the tasks to be done.

@jochenberger
Copy link
Contributor Author

facebook/react#10675 is probably also relevant.

@jquense
Copy link
Member

jquense commented Sep 14, 2017

@KagamiChan please feel free to jump in here. The tasks are to upgrade to the new createPortal api while (if possible) also supporting v15. So some amount of feature detecting and branching is needed. Portal should be the only component that needs an upgrade.

@KagamiChan
Copy link

thank you for your reply, will take some time to learn about this

@jochenberger
Copy link
Contributor Author

I just created #201 to make some progress on this. Any help is appreciated.

@jochenberger
Copy link
Contributor Author

@jquense, I don't think that this is the solution (see #201). I think that @billschaller pointed out the issue in #188 (comment). I got some of the tests to run by wrapping the div into a component that calls Modal.show it its componentDidMount. But I wonder if there is a way to do what @billschaller suggested without the need for an additional wrapper component.

jazzido added a commit to Datawheel/mondrian-rest-ui that referenced this issue Sep 26, 2017
@jochenberger jochenberger changed the title Modal does not work with React 16 (beta/RC) Modal does not work with React 16 Sep 27, 2017
@grantila
Copy link

FYI React 16 is released, so this just became a blocker for people to be able to upgrade.

@billschaller
Copy link

This shim has worked fine for us - it bypasses some functionality but it got us unblocked.

const {Modal} = require('react-overlays');

const focus = () => {};

const cDU = Modal.prototype.componentDidUpdate;

Modal.prototype.componentDidUpdate = function(prevProps: any) {
  if (this.focus !== focus) {
    this.focus = focus;
  }
  cDU.call(this, prevProps);
};

@Calyhre
Copy link

Calyhre commented Sep 28, 2017

😄 I'm also using this in the meantime :

import { Modal as ReactOverlayModal } from 'react-overlays';

class Modal extends ReactOverlayModal {
  focus = () => {};
}

export default Modal;

@jquense
Copy link
Member

jquense commented Oct 1, 2017

you can see that there are a few efforts to fix this. IF you want stuff to go faster jump in on the PR's and review/test them

@patsissons
Copy link

I dug into this a bit to see what the root problem was. The core problem is react-dom's commitAllLifeCycles invokes commitAttachRef after commitLifeCycles. This means that setModalNode (which assigns the local modalNode field) is invoked after componentDidMount (which calls onShow and by extension focus).

What this means is that (given that react-dom does not change its commitAllLifeCycles function), we remove the onShow from componentDidMount and move it to setModalNode. I have tested this and it most definitely works as expected.

  setModalNode = (ref) => {
    this.modalNode = ref;
    if (ref && this.props.show) {
      this.onShow();
    }
  }

as a temporary shim, this should work for most setups.

import { Modal } from 'react-overlays';
Modal.prototype.componentWillMount = function() {
  this.setModalNode = function(ref: any) {
    this.modalNode = ref;
    if (ref != null && this.props.show) {
      this.onShow();
    }
  }.bind(this);
};
Modal.prototype.componentDidMount = function() {
  this._isMounted = true;
};

@ptkoz
Copy link

ptkoz commented Oct 3, 2017

I'd just like to note that @patsissons solution obviously does not work when you're doing something like this:

class MyModal extends React.PureComponent {
    constructor(props) {
         super(props)
         this.state = { visible: false };
    }

    componentDidMount() {
         this.setState({ visible: true });
    }

    render() {
        return <Modal {...this.props} show={this.state.visible}> ... </Modal>
    }
}

as onShow is then called from Modal's componentDidUpdate, not componentDidMount.

// edit: fixed code

@jeremy-colin
Copy link

Hey! Anything we can do to help?

@TryingToImprove
Copy link

@jeremy-colin There seems to be some WIP pull requests.

@mglrahul
Copy link

hi guys,

i tried to use the patches provided here but couldn't able to do that. can anyone help me out in this matter. i already post my question here.

looking for help. @patsissons @pamelus @davidworkman9 @connorjburton @Calyhre

thanks for help in advance.

@connorjburton
Copy link

@mglrahul you are probably best off waiting for the official patch to be honest

@mglrahul
Copy link

@connorjburton actually i urgently need to fix the issue in my project. so if i get any working patch solution than that's fine, we can fix the temporary with the official update later. but right now i need a fix. if you can give me some idea it will be great.

i already try to integrate the patches mentioned above in my project, but couldn't be able to make it workable.

@patsissons
Copy link

@mglrahul see my post above (#188 (comment)) it addresses how to get this up and running with minimal side effects. The shim in the post should patch the react-overlay module to work in react 16. otherwise just downgrade to react 15 where the lifecycle sequence is compatible with these modals.

@mglrahul
Copy link

mglrahul commented Oct 11, 2017

hey @patsissons thanks for replying, i read #188 commit, but couldn't understand where to put the patch you provided. do i need to put it in component or js library. below is my component.

import { Button, Modal } from 'react-bootstrap';

export default class ModelFirst extends Component {
  constructor(props) {
    super(props);

    this.state = {
      showModal: false
    };

    this.open = this.open.bind(this);
    this.close = this.close.bind(this);
  }

  close() {
    this.setState({ showModal: false });
  }

  open() {
    console.log('open');
    this.setState({ showModal: true });
  }

  render() {
    return (
      <div>
        <p>Click to get the full Modal experience!</p>
        <Button
          bsStyle="primary"
          bsSize="large"
          onClick={this.open}
        >
          Launch demo modal
        </Button>

        <Modal show={this.state.showModal} onHide={this.close}>
          <Modal.Header closeButton>
            <Modal.Title>Modal heading</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <h4>Overflowing text to show scroll behavior</h4>
            <p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
            <p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
            <p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p>
          </Modal.Body>
          <Modal.Footer>
            <Button onClick={this.close}>Close</Button>
          </Modal.Footer>
        </Modal>
      </div>
    );
  }
};

this is the question i asked on stackoverflow.
I appreciate your help, thanks in advance. :-)

@seeden
Copy link

seeden commented Oct 11, 2017

If you are using webpack you need to use this fix like this:

import Modal from 'react-bootstrap/node_modules/react-overlays/lib/Modal';

Modal.prototype.componentWillMount = function componentWillMount() {
  this.focus = function focus() {};
};

@mglrahul
Copy link

@seeden i try to use your solution in the component but i get some error, below is the error i got

Modal.prototype.componentWillMount = function componentWillMount() {
     |        ^
  20 |     this.focus = () => {};
  21 |   };
  22 | 

i have put the code out of render in component.

@zdila
Copy link

zdila commented Oct 11, 2017

@mglrahul put it out of component

@erise133
Copy link

@mglrahul You can do that kind of walk around in your entry point for js files. main.js or index.js. Just make sure you have imported Modal from react-overlays

@astanciu
Copy link

Is this patch the "official" response for react-bootstrap on react16 or is there WIP to get this fixed properly?

@jharris4
Copy link

@astanciu #208 is the WIP. Looks like it's getting close to being ready...

@mglrahul
Copy link

finally i able to make it work, thanks to all the kind people @szczepanbarszczowski @zdila @seeden @patsissons @connorjburton

without all your help it won't work

@jharris4
Copy link

version 0.7.3 seems to have fixed the issue.

Thanks for the work on this!

jfly added a commit to jfly/worldcubeassociation.org that referenced this issue Oct 18, 2017
jfly added a commit to jfly/worldcubeassociation.org that referenced this issue Oct 23, 2017
jfly added a commit to thewca/worldcubeassociation.org that referenced this issue Oct 23, 2017
@geminiyellow
Copy link

still not working

TypeError: Cannot read property 'contains' of undefined
    at app-bundle-9f3367cd4c8da193f2df7875ec037f39ff0441e251ba61c728a43c8363174343.js:24030
    at Modal.focus (app-bundle-9f3367cd4c8da193f2df7875ec037f39ff0441e251ba61c728a43c8363174343.js:65592)
    at Modal.onShow (app-bundle-9f3367cd4c8da193f2df7875ec037f39ff0441e251ba61c728a43c8363174343.js:65521)
    at Modal.componentDidUpdate (app-bundle-9f3367cd4c8da193f2df7875ec037f39ff0441e251ba61c728a43c8363174343.js:65278)
    at commitLifeCycles (vendor-69769756228c5b97a31cdefe85d1499ffa9865cebae44c24682bb47a8949d3eb.js:20358)
    at c (vendor-69769756228c5b97a31cdefe85d1499ffa9865cebae44c24682bb47a8949d3eb.js:20369)
    at k (vendor-69769756228c5b97a31cdefe85d1499ffa9865cebae44c24682bb47a8949d3eb.js:20372)
    at p (vendor-69769756228c5b97a31cdefe85d1499ffa9865cebae44c24682bb47a8949d3eb.js:20373)
    at batchedUpdates (vendor-69769756228c5b97a31cdefe85d1499ffa9865cebae44c24682bb47a8949d3eb.js:20379)
    at qb (vendor-69769756228c5b97a31cdefe85d1499ffa9865cebae44c24682bb47a8949d3eb.js:20230)

@bernharduw
Copy link

@geminiyellow this has been fixed in 0.7.3, but not yet in the 0.8 branch (as of 0.8.2).

I worked around that issue by creating a custom Modal wrapper component which monkey-patches cDM and cDU as outlined above:

import Modal from 'react-overlays/lib/Modal';

const focus = () => {};

const cDU = Modal.prototype.componentDidUpdate;
const cDM = Modal.prototype.componentDidMount;

// react-overlays v0.8.2 doesn't work with React 16, so we have to monkey-patch it.
// TODO remove this once react-overlays is compatible with React 16.
Modal.prototype.componentDidUpdate = function componentDidUpdatePatched(prevProps: any) {
  if (this.focus !== focus) {
    this.focus = focus;
  }
  cDU.call(this, prevProps);
};

Modal.prototype.componentDidMount = function componentDidMountPatched() {
  if (this.focus !== focus) {
    this.focus = focus;
  }
  cDM.call(this);
};

export default Modal;

Once 0.7.3 was released, I just downgraded the react-overlays version from ^0.8.2 to ^0.7.3, so that patch isn't needed any more.

@geminiyellow
Copy link

@billschaller thank you 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests