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

fix(popover): dropdown does not flicker on firefox #10660

Merged
merged 10 commits into from
Aug 8, 2024

Conversation

liamdebeasi
Copy link
Contributor

@liamdebeasi liamdebeasi commented Jul 29, 2024

resolves #9925

Background

The usePopper hook uses useLayoutEffect. Whenever useLayoutEffect runs, the popover is either created or destroyed and then re-created. This hook has no dependencies, so it runs any time its parent component re-renders.

This triggers a quirk in Firefox on hover since the popover is destroyed and re-created on each hover (since hovering causes a state change via Downshift). More info about the issue can be found here.


The Fix

To fix this, I updated usePopper to accept a list of dependencies that are then passed to useLayoutEffect. This ensures that useLayoutEffect only runs when the deps change. This is important for popovers that are added to the DOM on load but do not have any content (and thus have a dimension of 0x0). Since the content has a dimension of 0x0, Popper cannot position the popover correctly. Once the popover is opened, the content is added, and we need to re-run the hook so Popper can reposition the popover correctly.


Testing

The following components should be tested since they use usePopper:

  • SymbolsPicker
  • ItemPopup
  • StoreHeading
  • Select
  • PressTip
  • Dropdown

Other Info

This fix should also provide a slight performance boost since DIM no longer needs to destroy and re-create the popover as often as it used to.

@liamdebeasi liamdebeasi changed the title fix: dropdown does not flicker on firefox fix(popovers): dropdown does not flicker on firefox Jul 29, 2024
@liamdebeasi liamdebeasi changed the title fix(popovers): dropdown does not flicker on firefox fix(popover): dropdown does not flicker on firefox Jul 29, 2024
* a popover when conditionally rendering the contents of the popover (thus
* causing the dimensions to potentially change).
*/
state?: boolean;

This comment was marked as outdated.

@bhollis
Copy link
Contributor

bhollis commented Aug 1, 2024

Awesome, glad to see a fix for this.

Longer term I'd love to see us do #8374 (Switch to Floating UI) or even swap to a CSS anchor positioning polyfill (though the one polyfill I've seen so far is not great).

@@ -160,5 +168,5 @@ export function usePopper({
}

return destroy;
});
}, [reference, contents, state]);
Copy link
Contributor

Choose a reason for hiding this comment

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

My original idea behind having the layout effect fire on every update was that I don't know what (if anything) has changed about the contents, so I don't know when exactly to re-position. This is made especially complicated by the fact that popper seems to have some bugs around its lifecycle (which afaik are fixed in floating-ui).

Testing around a bit, I can see that uses of Dropdown appear broken with this change - for example, the menu you can access from the three dots in the search bar.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for testing! I'll go back and take another look. It's likely that I missed a case I was not considering before.

Copy link
Contributor Author

@liamdebeasi liamdebeasi Aug 6, 2024

Choose a reason for hiding this comment

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

Ok I made some adjustments. The big change here is usePopper now accepts a dependency list. For the particular broken popovers you noted, both the isOpen state and the items list are listed as dependencies in addition to all the other deps in usePopper. This should resolve the problem you noted.

I opted to not touch the other usePopper implementations because they currently do not exhibit the reported bug.

@bhollis
Copy link
Contributor

bhollis commented Aug 1, 2024

Also if you're on the Discord, ping me and I'll add the contributor role for you.

Comment on lines 167 to 176
contents,
reference,
arrowClassName,
menuClassName,
boundarySelector,
placement,
offset,
fixed,
padding,
deps,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

React expects that all reactive values be listed as dependencies: https://react.dev/reference/react/useEffect#specifying-reactive-dependencies

Copy link
Contributor

Choose a reason for hiding this comment

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

Fair, though in practice many of these are immutable. Can't hurt, though.

What doesn't work is including deps directly like this - hooks' dependencies list won't recursively evaluate equality. So you probably want:

Suggested change
contents,
reference,
arrowClassName,
menuClassName,
boundarySelector,
placement,
offset,
fixed,
padding,
deps,
contents,
reference,
arrowClassName,
menuClassName,
boundarySelector,
placement,
offset,
fixed,
padding,
...deps,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yeah, so that causes a React warning since React can't statically analyze the dependencies that way. We can add a comment to ignore the rule, but wasn't sure if you'd be comfortable with that approach.


I can also remove the other refs if they are immutable, though that will cause React to log another warning since it expects them to be included as dependencies. Similarly, we can add a comment to ignore the rule if you'd like.

Copy link
Contributor

Choose a reason for hiding this comment

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

Probably the best would be to silence the warning about having a dynamic dependency list, but still include all the other dependencies.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All set!

@bhollis bhollis merged commit fab6f0c into DestinyItemManager:master Aug 8, 2024
6 checks passed
@liamdebeasi liamdebeasi deleted the ld/dropdown-render branch August 8, 2024 18:27
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

Successfully merging this pull request may close these issues.

Dropdown hover selection is weird on Firefox
2 participants