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

CommandBar: componentRefs get wiped out when resizing/re-rendering #7582

Closed
nikhilpuria opened this issue Jan 9, 2019 · 13 comments
Closed

Comments

@nikhilpuria
Copy link

nikhilpuria commented Jan 9, 2019

I am trying to use Calendar component with a Callout inside a Commandbar. By default the Calendar component does not auto close on selection and for that reason I call the dismissMenu() function on onSelectDate() of Calendar. But there is some issue around the setting of the ref. Its gets set only once and the second time it comes as null. If I give a unique key to the CommandBar (i.e force react to mount the whole CommandBar everytime then it works)

Environment Information

  • Package version(s): 6.106.3
  • Browser and OS versions: (fill this out if relevant)

Please provide a reproduction of the bug in a codepen:

https://codepen.io/nikhilpuria/pen/PXaaVP?editors=1010

Expected behavior:

componentRef is called only once

Actual behavior:

componentRef should be called everytime the component is rendered

Priorities and help requested:

Are you willing to submit a PR to fix? (Yes, No)

Requested priority: (Blocking, High, Normal, Low)

Products/sites affected: (if applicable)

@dzearing
Copy link
Member

dzearing commented Jan 9, 2019

I debugged into this, and found the culprit. @christiango for visability.

In your codepen, you're calling this.setState({}), which causes new items to be created and passed into the CommandBar. I debugged that just re-rendering your content component would cause the ref to become invalidated with a new button ref, and then it would clear it out with null.

Here's why!

The CommandBar interprets these as new, unmeasured items. They end up getting passed along to ResizeGroup, which will try to re-render and measure the items. The componentRef is then evaluated again because of the offscreen render, which resets the ref to the wrong, offscreen button. Then once resizegroup is done measuring, it removes the button, killing the ref.

There are 2 questions I have:

  1. Why should we re-render this button in the first place, when it has the same key as a previously rendered button? (@christiango may have the answer)

  2. As a short term fix, could we simply scrub componentRefs from being passed along to resize group, to avoid evaluating them? (@micahgodbolt and I are looking at this.)

@dzearing
Copy link
Member

dzearing commented Jan 9, 2019

Micah and I prototyped #2. Overall it would fix some, but not all, scenarios where componentRef could be used. For example, buttons can have menu items, which each might have sub sub sub menus, which may have items that have componentRefs to things rendered in the ResizeGroup.

So, I think we need to question if ResizeGroup really needs the "offscreen" render, or if so, is there any contextual way to not resolve componentRefs in this case. I would really prefer to avoid adding a ContextProvider to BaseComponent. The new useContext api would come in handy here.

@dzearing
Copy link
Member

dzearing commented Jan 9, 2019

What if we did all our rendering onscreen to avoid redundant rendering? would there be flicker?

Would IntersectionObserver help here?

@christiango
Copy link
Member

I do believe we were seeing a flicker on older browsers when doing the measurement on screen, but Micah was the first one to experiment with off screen rendering, so he might know more details.

With respect to your question David, ResizeGroup doesn't measure individual buttons, it measures the width of the entire group of buttons.

@micahgodbolt
Copy link
Member

Is there a way to clone the current DOM (excluding refs) and display that while the original control resizes? No clue how technically possible that is, but it'd be a different way to approach the problem.

@christiango
Copy link
Member

Sorry, I accidentally closed this. I think we would have to go outside React to do the kind of thing you are suggesting.

@Vitalius1 Vitalius1 assigned dzearing and unassigned Vitalius1 Jan 9, 2019
@dzearing
Copy link
Member

I had thought about potentially using renderToString.. but I think that would bloat bundle sizes.

I suspect that the solution of filtering out componentRef for offscreen renders might be just good enough. We aren't rendering button menus or anything, so those would not be evaluated.

@dzearing
Copy link
Member

@micahgodbolt or @christiango wanna take a stab here? I'm going to try and fix the focuszone focus restore issue.

@christiango
Copy link
Member

I won't be able to help out here unfortunately. I am currently not working on UX to help us with some Word deliverables.

@christiango
Copy link
Member

I can get some eyes from our team to help test the change against the Ribbon if we think there is a regression risk

@KeiraYang
Copy link

KeiraYang commented Jan 22, 2019

Hi. I also encountered the similar issue. Instead, I want to get the command bar button element by ref. When I invoke the ref callback in componentDidMount, I'll get the ref under div with attribute data-automation-id="visibleContent", which is the right one for commandbar button. But if I invoke the ref callback in componentDidUpdate, I'll get the ref under div with style="position: fixed; visibility: hidden;". So I always get null.

When I debug, I got this two similar elements for commandbar:
image

Is there any way to let me always get a correct ref? I'm really looking forward to your reply.

@micahgodbolt micahgodbolt changed the title componentRef getting called only once for CommandBar items CommandBar: componentRefs get wiped out when resizing/re-rendering Jan 2, 2020
@khmakoto khmakoto self-assigned this May 24, 2021
@hoovercj
Copy link
Member

This goes beyond "componentRefs", it also makes getting html refs to elements rendered within a resize group impractical.

For example, we are using teaching tips to point to elements and we have been trying to use element refs rather than selectors but these refs are not stable and are often set to null when the element is rendered in a resize group due to the reasons set above.

We will likely be forced to use selectors instead, but there are reasons why we would prefer to use element refs, so if there is a way to prevent them from being nulled out with off-screen rendering, that would be great.

@msft-fluent-ui-bot
Copy link
Collaborator

Because this issue has not had activity for over 150 days, we're automatically closing it for house-keeping purposes.

Still require assistance? Please, create a new issue with up-to date details.

@msft-fluent-ui-bot msft-fluent-ui-bot added the Resolution: Soft Close Soft closing inactive issues over a certain period label Jan 22, 2022
@microsoft microsoft locked as resolved and limited conversation to collaborators Feb 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

10 participants