这个教程会帮助你学会如何在常见的场景搭配TypeScript使用 React Three Fiber

Using with TypeScript

本教程假定您具有一些 React 和 TypeScript 的知识,并且将基于此初始codesandbox,因此只需fork它并跟随即可!

Typeing with useRef

React 的 useRef 不会自动推断类型,即使将其指向一个类型化的 ref。您可以通过在 useRef 的泛型中传递类型来手动为 ref 添加类型:

import { useRef, useEffect } from 'react'
import { Mesh } from 'three'

function Box(props) {
  const meshRef = useRef<Mesh>(null!)

  useEffect(() => {
    console.log(Boolean(meshRef.current))
  }, [])

  return (
    <mesh {...props} ref={meshRef}>
      <boxGeometry />
      <meshBasicMaterial />
    </mesh>
  )
}

感叹号是一个非空断言运算符,它会告诉TS,当我们在effect中访问它时,ref.current是有定义的。

Typeing shorthand props

react-three-fiber 接受缩写的 props,如标量、字符串和数组,因此您可以声明性地设置属性而不会产生副作用。

以下是不同变体的 props:

import { Euler, Vector3, Color } from 'three'

rotation: Euler || [x, y, z]
position: Vector3 || [x, y, z] || scalar
color: Color || 'hotpink' || 0xffffff

每个属性都有扩展类型,您可以从中提取这些属性的类型。

import { Euler, Vector3, Color } from '@react-three/fiber'
// or
// import { ReactThreeFiber } from '@react-three/fiber'
// ReactThreeFiber.Euler, ReactThreeFiber.Vector3, etc.

rotation: Euler
position: Vector3
color: Color

如果您正在组件外部输入属性(例如 store或hook),则这特别有用。

Node Helpers

react-three-fiber也可以接受第三方元素并将其通过 extend 方法进行扩展。

import { useRef, useEffect } from 'react'
import { GridHelper } from 'three'
import { extend } from '@react-three/fiber'

// 创建自定义元素
class CustomElement extends GridHelper {}

// 通过 extend 方式 reconciler 会知道如何处理它
extend({ CustomElement })

扩展过后就可以直接在项目代码中用 JSX 的方式进行使用这些元素了。

但是这样的声明式的写法要注意一个问题, TypeScript 不会知道它们或它们的 props。

// error: 'customElement' 不存在于 type 'JSX.IntrinsicElements'

<customElement />

Exported types

react-three-fiber导出了一些heplers 类型,您可以使用它们来定义不同类型的节点。这些节点将会对我们添加到全局JSX名称空间的元素进行类型标注。

Node
Object3DNode
BufferGeometryNode
MaterialNode
LightNode

Extending ThreeElements

因为我们得自定义 Element 是一个对象,我们可以使用Object3DNode类型去定义它。

import { useRef, useEffect } from 'react'
import { GridHelper } from 'three'
import { extend, Object3DNode } from '@react-three/fiber'

// Create our custom element
class CustomElement extends GridHelper {}

// Extend so the reconciler will learn about it
extend({ CustomElement })

// Add types to ThreeElements elements so primitives pick up on it
declare module '@react-three/fiber' {
  interface ThreeElements {
    customElement: Object3DNode<CustomElement, typeof CustomElement>
  }
}

// react-three-fiber will create your custom component and TypeScript will understand it
<customComponent />

react-three-fiber 是可扩展的而且也导出自己的内部类型,比如 render props、canvas props 还有 events 等等。

// Event raycaster intersection
Intersection

// `useFrame` internal subscription and render callback
Subscription
RenderCallback

// `useThree`'s returned internal state
RootState
Performance
Dpr
Size
Viewport
Camera

// Canvas props
Props

// Supported events
Events

// Event manager signature (is completely modular)
EventManager

// Wraps a platform event as it's passed through the event manager
ThreeEvent