motiondivision / motion

A modern animation library for React and JavaScript
https://motion.dev
MIT License
25.28k stars 833 forks source link

useMotionValue of component A affected by onMouse events of component B that has nothing to do with A #2894

Open EricYoung37 opened 18 hours ago

EricYoung37 commented 18 hours ago

1. Describe the bug I'm building a React project. I have ComponentA.js and ComponentB.js that have nothing to do with each other except rendered in the same page.

In ComponentA.js, I have

// A
const dragX = const dragX = useMotionValue(0);
console.log(dragX);

In ComponentB.js, I have

// B
// I personally don't think the tag matters here
<video
  onMouseOver={() => setFocus(true)}
  onMouseOut={() => setFocus(false)}
  onEnded={onEndedLoop}
  src="/videos/something.mp4"
  muted
  playsInline
/>

Everytime the onMouse event listeners in B are triggered, dragX in A changes (can be seen from console.log(dragX)). This leads to unwanted animation effects on A.

If I use

// B
<video
  onMouseOver={() => {console.log("message 1")}}
  onMouseOut={() => {console.log("message 2")}}
  // omit repeated code for succinctness
/>

in B, then dragX in A won't change (no output from console.log(dragX)).

Also, if I have

// A
console.log(dragX.get())

in A, then hovering in B makes the console produce lots of 0s (by comparison, dragging in A produces meaningful coordinates, which is intended).

2. IMPORTANT: Provide a CodeSandbox reproduction of the bug

I wish I could provide code here, but I'm working on a private project with much code, and I personally think it could be distracting if trivial code is present.

3. Expected behavior

Hovering in B should not impact dragX or useMotionValue in A.

4. Video or screenshots

useMotionValue(0) (in A) is triggered when hovering (on an element in B). Note dragX.get() produces 0s.

https://github.com/user-attachments/assets/fc9a9c5a-ccb0-4750-a114-3fbc1922d3d5

useMotionValue(0) (in A) is triggered when interacting with an element (the carousel) in A. Note dragX.get() produces meaningful coordinates.

https://github.com/user-attachments/assets/7a1cb9cd-c953-4116-a2e2-d8f9299604fb

6. Environment details Windows 10 22H2 Chrome Version 130.0.6723.119 (Official Build) (64-bit) React 18.3.1 (problem happens even without StrictMode)

mattgperry commented 18 hours ago

Unfortunately I’m going to need a sandbox to look into this further. My off the top of the head idea is that focusing is doing something to the videos layout?

EricYoung37 commented 16 hours ago

Thanks for reaching out!

So focus is just a useState to identify if the user hovers on the video. Layout of the video is never changed.

Below is the related code.

// ComponentB.js

const [focus, setFocus] = useState(false);

const loop = () => {
  ref.current.play();
};

const pauseLoop = () => {
  ref.current.pause();
};

const onEndedLoop = () => {
  if (focus) loop(); // when ended check if its focused then loop
};

useEffect(() => {
  if (focus) loop(); // when focused then loop
  if (!focus) pauseLoop(); // when not focused then pause loop
}, [focus]);

return (
<div>
  // ... omit for succinctness
  <video
    ref={ref}
    onMouseOver={() => setFocus(true)}
    onMouseOut={() => setFocus(false)}
    onEnded={onEndedLoop}
    src="/videos/something.mp4"
    muted
    playsInline
  />
  // ... omit for succinctness
</div>
);

I'm not sure if I'm able to write a working demo in a sandbox because there's much code involved. I'll need to factor things out, reorganize, and simplify, which would take me some time.

Is it possible that useMotionValue somehow monitors changes of the entire page layout rather than just the component it's located in? That way useMotionValue in A would be affected by onMouse events of B in the same page layout.