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

TransformControls does not work (flicker on hover, not draggable) when setting state in useFrame() #2226

Open
AndrewRayCode opened this issue Nov 21, 2024 · 3 comments
Labels
bug Something isn't working

Comments

@AndrewRayCode
Copy link

AndrewRayCode commented Nov 21, 2024

Codesandbox to reproduce: https://codesandbox.io/p/sandbox/react-three-fiber-forked-8tqxgj?file=%2Fsrc%2Fcomponents%2FBox.jsx%3A1%2C1-23%2C1

  • three version: 0.170.0
  • @react-three/fiber version: 8.17.10
  • @react-three/drei version: 9.117.0
  • node version: n/a
  • npm (or yarn) version: n/a

Problem description:

TransformControls don't work when you call setState in useFrame, including both react and zustand setters.

Hovering over the transform controls results in flickering, and they aren't draggable.

Relevant code:

import React from "react";
import { useState } from "react";
import { useFrame } from "@react-three/fiber";

import { TransformControls } from "@react-three/drei";

const Box = () => {
  const [state, setState] = useState();
  useFrame(() => {
    setState(Date.now());
  });
  return (
    <TransformControls mode="translate" translationSnap={0.5}>
      <mesh position={[0, 1, 0]}>
        <boxGeometry attach="geometry" />
        <meshBasicMaterial attach="material" wireframe="true" color="hotpink" />
      </mesh>
    </TransformControls>
  );
};

Suggested solution:

This should(?) work out of the box? Removing the setState causes it to work, but that is not an acceptable solution.

I note this does work if you move the useFrame() to the Plane.js component in the scene above - aka if it's in a sibling component.

This does not work if the parent component of the one containing the <TransformControls /> contains the useFrame/setState.

This also does not work if you add a key={0} prop to the TransformControls, which I tried to see if it's from mounting/unmounting.

@AndrewRayCode AndrewRayCode added the bug Something isn't working label Nov 21, 2024
@abernier
Copy link
Member

abernier commented Nov 21, 2024

https://r3f.docs.pmnd.rs/api/hooks#useframe

Be careful about what you do inside useFrame! You should never setState in there!

@AndrewRayCode
Copy link
Author

@abernier I see ... wrapping my head around how to update state outside of useFrame - although it's unclear to me if that's directly related to this issue. If I set state intermittently, not every frame, it looks like it would cause the transformcontrols to break the dragging behavior on that frame

@krispya
Copy link
Member

krispya commented Nov 22, 2024

The issue is that the TransformControls is not being memoized. You can see a fix here: https://codesandbox.io/p/sandbox/react-three-fiber-forked-8tqxgj

const Box = () => {
  const [state, setState] = useState();
  useFrame(() => {
    setState(Date.now());
  });
  return <Inner />;
};

export default Box;

const Inner = React.memo(() => {
  return (
    <TransformControls mode="translate" translationSnap={0.5}>
      <mesh position={[0, 1, 0]}>
        <boxGeometry attach="geometry" />
        <meshBasicMaterial attach="material" wireframe="true" color="hotpink" />
      </mesh>
    </TransformControls>
  );
});

We should do this in the component itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants