useFrame hook generate the error R3F: Hooks can only be used within the Canvas component!

Hi everyone! This is my first time posting here, and unfortunately, it is because of an error.

Here is the sandbox link of the code that, surprisingly, works fine. In my local view, I get the following error:

I don’t understand where I could have done something wrong.
The error appears every time I save the code, try to scroll, or change the visualization to test the responsiveness.

PS: the versions of react and react-dom match.

Thank you in advance for your time!

I can get that but it doesn’t blow my mind.

Hello 0xMari san.
Are you using useFrame outside of a Canvas? You’ll get that error if you try to use hooks like useFrame or useThree outside of the component that describes the R3F’s Canvas.
For example, the following is a bad example.
This is because hooks functions such as useFrame are being used outside of the Canvas.

export const Scene = () => {

  // X: Error
  useFrame(() => {})

  return (
    <Canvas>
    </Canvas>
  )
}

The correct example is as follows:

export const Scene = () => {

  return (
    <Canvas>
      <Pointer />
    </Canvas>
  )
}

const Pointer = () => {

  // O (Correct)
  useFrame(() => {})

  return (
    <></>
  )
}

Details Documents: React Three Fiber Documentation

1 Like

Hi ShoOsaka,
i am using useFrame in the correct way, as stated in the documentation, in the functions MetaBall and Pointer (I copied this example https://codesandbox.io/p/sandbox/metaballs-yro193?file=%2Fsrc%2FApp.js ).

function MetaBall({ color, vec = new THREE.Vector3(), ...props }) {
  const api = useRef();
  useFrame((state, delta) => {
    delta = Math.min(delta, 0.1);
    try {
      api.current.applyImpulse(
        vec
          .copy(api.current.translation())
          .normalize()
          .multiplyScalar(delta * -0.05)
      );
    } catch (e) {}
  });
  return (
    <RigidBody
      ref={api}
      colliders={false}
      linearDamping={4}
      angularDamping={0.95}
      {...props}
    >
      <MarchingCube strength={0.35} subtract={6} color={color} />
      <BallCollider args={[0.1]} type="dynamic" />
    </RigidBody>
  );
}

function Pointer({ vec = new THREE.Vector3() }) {
  const ref = useRef();
  useFrame(({ pointer, viewport }) => {
    const { width, height } = viewport.getCurrentViewport();
    vec.set(pointer.x * (width / 2), pointer.y * (height / 2), 0);
    try {
      ref.current.setNextKinematicTranslation(vec);
    } catch (e) {}
  });
  return (
    <RigidBody type="kinematicPosition" colliders={false} ref={ref}>
      <MarchingCube strength={0.5} subtract={10} color="orange" />
      <BallCollider args={[0.1]} type="dynamic" />
    </RigidBody>
  );
}```

I resolved the issue by recreating a new react app. I don’t know where it broke the first time but now everything is working.