在三个 JS useFrame 钩子中使用 refs

Using refs in Three JS useFrame hook

使用react-three-fiber经常需要使用refs来操作场景中的物体。例如,我们可能希望在每一帧渲染中移动网格的位置(参见下面的代码)。

但是,打字稿中的引用总是可能未定义。所以我们在操作它之前必须检查我们的 meshRef 是否是当前的:

  useFrame((state) => {
    if (meshRef.current) {
      meshRef.current.position.add(new Vector3(1, 1, 1));
    }
  });

但我想我们希望 useFrame 挂钩中的代码得到高度优化。如果我们使用常规 javascript 反应,就不需要 if(meshRef.current)。所以似乎仅仅通过使用打字稿,我们就牺牲了一些性能。

有没有什么方法可以解决这个问题而不涉及告诉打字稿编译器忽略潜在的未定义值?即 //@ts-ignore

完整代码示例:

import React, { useRef } from "react";
import { Canvas, extend, useFrame, useThree } from "@react-three/fiber";
import "./styles.css";
import { Mesh, Vector3 } from "three";

const Scene = (): JSX.Element => {
  const meshRef = useRef<Mesh>();
  useFrame((state) => {
    if (meshRef.current) {
      meshRef.current.position.add(new Vector3(1, 1, 1));
    }
  });

  return (
    <Canvas camera={{ fov: 75, position: [0, 0, 70] }}>
      <mesh ref={meshRef}>
        <boxBufferGeometry args={[10, 10, 1]} />
      </mesh>
    </Canvas>
  );
};

export default Scene;

您可以使用 ! 后缀强制将可选的 属性 视为必需的。

const ref = useRef<{ someObj: true }>()
ref.current!.someObj // typescript allows this

但是,这不是类型安全的。当 ref 为 undefined 时,第一次 运行 肯定会崩溃。但是,如果您可以绝对确定当 ref 有值时此代码仅 运行s,那么它应该可以工作。


不过我不推荐它。您正在邀请崩溃,而您没有意识到那里实际上可能缺少价值。

我不推荐它的第二个原因是你试图避免的这个检查真的真的快。

结帐 this benchmark 比较只是做这件事:

for (const obj of data) {
  result = result + obj.num;
}

以及你在哪里检查某物的存在然后做这件事:

for (const obj of data) {
  if (obj.num) {
    result = result + obj.num;
  }
}

在我的机器上,第二个慢了不到 5%。这是每个循环检查 1,000 次的最坏情况。如果您每帧只检查一次值是否存在,那么对性能的影响将非常小。

简而言之,像这样的无效检查并不是您的 webgl 应用程序运行缓慢的原因。