React-modal: ref is called after componentDidUpdate?

Created on 2 Mar 2017  ·  10Comments  ·  Source: reactjs/react-modal

Summary:

ref is called after componentDidUpdate

Steps to reproduce:

  1. Attach a ref in any component in the children of the modal
  2. The componentDidUpdate will get called before ref get attached to any children of the modal.

Expected behavior:

ref should get attached before componentDidUpdate

Additional notes:

I created a couple codepens to further explain this issue.

This codepen will reproduce this bug. Simply open the console, and click the Trigger Modal button. You should see two log messages, "componentDidUpdate" and follow by a "attach ref".

This codepen will show a normal react lift cycle if I remove change the Modal component to a div. When you click Trigger Modal button, you should see two "attach ref" follow by a "componentDidUpdate" after clicking the Tigger Modal button.

This codepen is a workaround I discovered. Open up the console, and click Tigger Modal, then click the number button. You should see two "attach ref" follow by a "componentDidUpdate" after clicking the number button.
Basically, if you can handle all the state and update in a component without declaring as the direct children of Modal, then you can create another component to wrap around all the logic, and put that component as the child of the Modal component.

I think this behavior would surprise a lot of people if they need the correct sequence of attaching ref and componentDidUpdate. I skimmed through the source a little bit, and I think it's likely relate to how ModalPortal get created. I think at the very least this needs to be either documented or fixed.

discussion

All 10 comments

Just got burned by this for a bit. Definitely a gotcha.

Just got burned by this as well.

Yes this doesn't seem like the behavior one would expect, +1

@stevenguh @griffinmichl @MrRacoon @micdah and everyone.

This is the "expected" behavior when you create a Modal (note that ModalPortal is not rendered if not opened, so no refs yet).

The lifecycle is actually correct. On the class ExampleApp, the refs will be built after the update, since the ModalPortal will be mounted after this update. Your ModalContent wrapper works as expected, because the refs are local to the class.

Hope now it's explained why it works this way.

@diasbruno I've read and reread your explanation here multiple times and I'm not sure I understand what you're saying. I feel like there's some fundamental understanding of how react modal works that I'm lacking the context of to understand this. Is there an article that explains the fundamentals of react-modal that you could point us towards?

I only ask because we got burned by this as well and it made me realize I don't completely understand this library. I'm leaning towards enacting a pattern for us that says all child content inside of modal should be it's own component, to avoid any unintended side-effects like this. Would you recommend this practice?

Thank you for your help and your work on this great lib!

@outdooricon Oh my...That was the worst explanation 🤦‍♂️ .

Ref: Adding a Ref to a DOM Element

ModalPortal.js#L301

This line will prevent any children from been mounted on the react tree, so if the modal is closed the ref callback won't be called, only when the modal is open.

I'm still really unclear how to solve this. I want the close button to be focused as soon as the modal opens. Can someone provide an example as to how to accomplish this? I've tried callinghandleOpenModal() and that still seems to happen before my ref has been set.

Totally agreed @stevenguh. I had the same problem.

Issue : ref in componentDidUpdate is ref of element of "render before", not the "updated render". It's a bug

+1

@erin-doyle any update?

@ysz this is not my library so no update from me. IIRC in the project where I was using this I ended up having to set:
shouldFocusAfterRender={true}
shouldReturnFocusAfterClose={false}

I gave up trying to set focus to anything specific within the modal when it opens and had to add code managing focus explicitly on onRequestClose to make sure the focus returns to the corrrect location when the modal closes.

Was this page helpful?
0 / 5 - 0 ratings