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

can't forward ref to ThreeView #6

Closed
bvkimball opened this issue Sep 13, 2021 · 3 comments · Fixed by #7
Closed

can't forward ref to ThreeView #6

bvkimball opened this issue Sep 13, 2021 · 3 comments · Fixed by #7

Comments

@bvkimball
Copy link
Contributor

bvkimball commented Sep 13, 2021

When trying to use with @react-three/cannon with react-ecs you need to pass the ref to the mesh, but the "ref" is overwritten by ThreeView when it clones the element.

I wrote a hack to basically to add a ref to ThreeView and merge that with the internalRef of ThreeView but thats not working.

import { Entity } from '@react-ecs/core'
import { ThreeView } from '@react-ecs/three'
import { useCylinder } from '@react-three/cannon'
import React from 'react'
import { PhysicsRef } from '../facets'

export const Pillar: React.FC<any> = ({ args = [0.7, 0.7, 5, 16], ...props }) => {
  const [ref, api] = useCylinder(() => ({ mass: 10, args, ...props }))
  return (
    <Entity>
      <ThreeView>
        <mesh ref={ref} castShadow>
          <cylinderGeometry args={args} />
          <meshNormalMaterial />
        </mesh>
      </ThreeView>
      <PhysicsRef target={ref} api={api} />
    </Entity>
  )
}
@Honga1
Copy link
Contributor

Honga1 commented Sep 13, 2021

@bvkimball

Hi Brian, below is my solution to your issue. Hope it helps!

import { EntityContext } from '@react-ecs/core'
import React, {
  Children,
  Component,
  ContextType,
  createRef,
  ReactElement,
  RefObject,
} from 'react'
import { Object3D } from 'three'
import mergeRefs from 'react-merge-refs'

export interface ThreeViewProps {
  children: ReactElement
  innerRef?: RefObject<Object3D>
}

/**
 * A modification of https://github.com/dustinlacewell/react-ecs/blob/master/libs/three/src/components/ThreeView/index.tsx
 * Adds forwarding the ref for the contained object
 */
export class ThreeView extends Component<ThreeViewProps> {
  static contextType = EntityContext
  declare context: ContextType<typeof EntityContext>
  public readonly ref: RefObject<Object3D>

  constructor(props: ThreeViewProps) {
    super(props)
    this.ref = createRef<Object3D>()
  }

  get object3d() {
    return this.ref.current!
  }

  componentDidMount() {
    const entity = this.context!
    entity.add(this as NonNullable<ThreeView>)
  }

  render() {
    if (Children.count(this.props.children) !== 1) {
      throw new Error('<ThreeView /> must have a single child.')
    }

    return (
      <>
        {React.cloneElement(this.props.children, {
          ref: this.props.innerRef
            ? mergeRefs([this.ref, this.props.innerRef])
            : this.ref,
        })}
      </>
    )
  }
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
;(ThreeView as any).__componentClassId__ = 100

@dustinlacewell
Copy link
Owner

I'd love to invite you guys as maintainers if you'd be open to that.

@bvkimball
Copy link
Contributor Author

@Honga1 that is where i basically ended up too!

@dustinlacewell I will work on a PR with this and an example with use-cannon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants