1- import { useFrame , useThree } from '@react-three/fiber'
21import * as React from 'react'
32import { Object3D } from 'three'
3+ import { useThree , useFrame } from '@react-three/fiber'
4+ import { Falsey } from 'utility-types'
45
56type HelperType = Object3D & { update : ( ) => void ; dispose : ( ) => void }
6- type HelperConstructor = new ( ...args : any [ ] ) => HelperType
7+ type HelperConstructor = new ( ...args : any [ ] ) => any
78type HelperArgs < T > = T extends [ infer _ , ...infer R ] ? R : never
89
10+ export function useHelper < T extends HelperConstructor > (
11+ object3D : React . MutableRefObject < Object3D > | Falsey ,
12+ helperConstructor : T ,
13+ ...args : HelperArgs < ConstructorParameters < T > >
14+ ) {
15+ const helper = React . useRef < HelperType > ( )
16+ const scene = useThree ( ( state ) => state . scene )
17+ React . useLayoutEffect ( ( ) => {
18+ let currentHelper : HelperType = undefined !
19+
20+ if ( object3D && object3D ?. current && helperConstructor ) {
21+ helper . current = currentHelper = new ( helperConstructor as any ) ( object3D . current , ...args )
22+ }
23+
24+ if ( currentHelper ) {
25+ // Prevent the helpers from blocking rays
26+ currentHelper . traverse ( ( child ) => ( child . raycast = ( ) => null ) )
27+ scene . add ( currentHelper )
28+ return ( ) => {
29+ helper . current = undefined
30+ scene . remove ( currentHelper )
31+ currentHelper . dispose ?.( )
32+ }
33+ }
34+ } , [ scene , helperConstructor , object3D , ...args ] )
35+
36+ useFrame ( ( ) => void helper . current ?. update ?.( ) )
37+ return helper
38+ }
39+
40+ //
41+
942export type HelperProps < T extends HelperConstructor > = {
1043 type : T
1144 args ?: HelperArgs < ConstructorParameters < T > >
@@ -15,33 +48,14 @@ export const Helper = <T extends HelperConstructor>({
1548 type : helperConstructor ,
1649 args = [ ] as never ,
1750} : HelperProps < T > ) => {
18- const objectRef = React . useRef < Object3D > ( null ! )
19- const helperRef = React . useRef < HelperType > ( )
20-
21- const scene = useThree ( ( state ) => state . scene )
51+ const thisRef = React . useRef < Object3D > ( null ! )
52+ const parentRef = React . useRef < Object3D > ( null ! )
2253
2354 React . useLayoutEffect ( ( ) => {
24- const parent = objectRef . current ?. parent
25-
26- if ( ! helperConstructor || ! parent ) return
27-
28- const helper = new helperConstructor ( parent , ...args )
29-
30- helperRef . current = helper
31-
32- // Prevent the helpers from blocking rays
33- helper . traverse ( ( child ) => ( child . raycast = ( ) => null ) )
34-
35- scene . add ( helper )
36-
37- return ( ) => {
38- helperRef . current = undefined
39- scene . remove ( helper )
40- helper . dispose ?.( )
41- }
42- } , [ scene , helperConstructor , ...args ] )
55+ parentRef . current = thisRef . current . parent !
56+ } )
4357
44- useFrame ( ( ) => void helperRef . current ?. update ?. ( ) )
58+ useHelper ( parentRef , helperConstructor , ... args )
4559
46- return < object3D ref = { objectRef } />
60+ return < object3D ref = { thisRef } />
4761}
0 commit comments