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

Inproper usage of refs throughout the code base #7406

Open
1 of 2 tasks
Bastian opened this issue Jan 24, 2025 · 2 comments
Open
1 of 2 tasks

Inproper usage of refs throughout the code base #7406

Bastian opened this issue Jan 24, 2025 · 2 comments

Comments

@Bastian
Copy link
Contributor

Bastian commented Jan 24, 2025

Dependencies check up

  • I have verified that I use latest version of all @mantine/* packages

What version of @mantine/* packages do you have in package.json?

7.16.0

What package has an issue?

@mantine/hooks

What framework do you use?

Vite

In which browsers you can reproduce the issue?

All

Describe the bug

While working on #7404, I noticed that there are many places that depend on ref values inside useEffect hooks. Sometimes the ref value is included in the dependency array (for example in the useHover hook [1]) and sometimes it is used inside a useEffect hook but not declared as a dependency at all (for example in the useMove hook [2]).

Both are problematic and are a source of bugs. Updates to a ref value do not trigger re-renders and thus the code of the useEffect hook will never be executed in some scenarios.

Here are two sandbox examples, illustrating the bug:

The useHover one does not work after clicking the "Show Div" button, but a triggering a re-rendering "fixes" it, because the value of ref.current is included in the dependency array:

chrome_9D4PmPSNAm.mp4

The useMove one never recovers, even after re-renders, because ref.current is not included in the dependency array:

chrome_FNBs4qzPem.mp4

These are just two examples, but there are many others, and since these hooks are also used in the Mantine components, they are most likely affected as well.

[1] ref.current in dependency array of useHover

useEffect(() => {
if (ref.current) {
ref.current.addEventListener('mouseenter', onMouseEnter);
ref.current.addEventListener('mouseleave', onMouseLeave);
return () => {
ref.current?.removeEventListener('mouseenter', onMouseEnter);
ref.current?.removeEventListener('mouseleave', onMouseLeave);
};
}
return undefined;
}, [ref.current]);

[2] ref.current used in useEffect hook but not included in dependency array

ref.current?.addEventListener('mousedown', onMouseDown);
ref.current?.addEventListener('touchstart', onTouchStart, { passive: false });
return () => {
if (ref.current) {
ref.current.removeEventListener('mousedown', onMouseDown);
ref.current.removeEventListener('touchstart', onTouchStart);
}
};
}, [dir, onChange]);

If possible, include a link to a codesandbox with a minimal reproduction

No response

Possible fix

Refs should not be used in these cases. Instead the html element should be stored inside a React state which triggers a re-render when the value changes.

import { useCallback, useEffect, useState } from 'react';


export function useHover<T extends HTMLElement = any>() {
  const [hovered, setHovered] = useState(false);
  const [node, setNode] = useState<T>();
  const onMouseEnter = useCallback(() => setHovered(true), []);
  const onMouseLeave = useCallback(() => setHovered(false), []);

  useEffect(() => {
    if (node) {
      node.addEventListener('mouseenter', onMouseEnter);
      node.addEventListener('mouseleave', onMouseLeave);

      return () => {
        node?.removeEventListener('mouseenter', onMouseEnter);
        node?.removeEventListener('mouseleave', onMouseLeave);
      };
    }

    return undefined;
  }, [node]);

  return { ref: setNode, hovered };
}

The usage for the user remains the same, but strictly speaking this is a breaking change.

Self-service

  • I would be willing to implement a fix for this issue
@Bastian
Copy link
Contributor Author

Bastian commented Jan 26, 2025

@rtivital My pull request #7404 did not fix this bug, this is a different and bigger problem. Can you please reopen this issue?

@rtivital rtivital reopened this Jan 26, 2025
@DanielSegal1
Copy link

Would like to have that assigned to me
Already fixed useHover and moving to next hooks right now
thanks!

This was referenced Feb 15, 2025
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

3 participants