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

[Menu] Fix custom anchor positioning #609

Merged
merged 8 commits into from
Sep 17, 2024

Conversation

michaldudak
Copy link
Member

@michaldudak michaldudak commented Sep 13, 2024

Using the anchor prop works only in development mode, when React runs the effect twice. This is because we read the anchor ref in useLayoutEffect, when it hasn't been set yet. Additionally, passing the Element directly didn't work as well.

This PR adds an extra effect after the first render, that checks if the ref value changed after useLayoutEffect was called. If so, it calls setPositionReference again with the ref value.

@mui-bot
Copy link

mui-bot commented Sep 13, 2024

Netlify deploy preview

https://deploy-preview-609--base-ui.netlify.app/

Generated by 🚫 dangerJS against e2362e3

// Therefore, if the anchor is a ref, we need to update the position reference in useEffect.
const resolvedAnchor = typeof anchor === 'function' ? anchor() : anchor;
if (isRef(resolvedAnchor) && resolvedAnchor.current !== registeredPositionReference.current) {
refs.setPositionReference(resolvedAnchor.current);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is flushSync necessary now, if there will be a flicker?

Copy link
Member Author

Choose a reason for hiding this comment

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

I haven't noticed it flickering. With the menu initially open, even with 20x CPU slowdown, the popup appears only near the anchor.

@michaldudak michaldudak marked this pull request as ready for review September 16, 2024 15:53
const anchorRef = useLatestRef(anchor);
const rerender = useForcedRerendering();

const registeredPositionReference = React.useRef<Element | VirtualElement | null>(null);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const registeredPositionReference = React.useRef<Element | VirtualElement | null>(null);
const registeredPositionReferenceRef = React.useRef<Element | VirtualElement | null>(null);

Comment on lines 207 to 208
const rerender = useForcedRerendering();

Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't seem to be actually used? It's just in the dep array

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, it's a leftover from a previous attempt.

@michaldudak michaldudak added component: menu This is the name of the generic UI component, not the React module! bug 🐛 Something doesn't work labels Sep 17, 2024
@michaldudak michaldudak merged commit 1ab27b0 into mui:master Sep 17, 2024
20 checks passed
@michaldudak michaldudak deleted the positioner-anchor branch September 17, 2024 09:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: menu This is the name of the generic UI component, not the React module!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants