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

Docs need forwardRef example and a slightly more advanced real world usage example #3119

Open
tripdragon opened this issue Dec 12, 2023 · 2 comments

Comments

@tripdragon
Copy link

tripdragon commented Dec 12, 2023

Once you get past the simple demo tutorials for useRef and starting building a real app with nested models and logic, the complexity level skyrockets.

For one all custom components that will need a useRef in the parent require the component be built with forwardRef() which at the very start is not at all obvious nor clear but its doable, but is no where within the docs

Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()

extend() looked like its a go to but I see that all that does is make react dom elements so you can do lowercase <customThing /> object3ds

After that if you need a reference to the internal object with the ref, you can no longer just use a useRef AND a forward ref, you have to string together some other monster, this examples monster landed on useImperativeHandle which is not a well discussed hook in react from my poking around

And once you use that it sets up a nested quagmire as you now have to assign any functions and members you need as it blanks out the ref.current.position for example. You can work around that and pass a pass of the ref to the object
But im going down a tunnel of klugery that should be as simple as
maObject.position.set() and i am stuck looking at this now playerRef.current.mainObject.current.mainObject
and wondering what im doing wrong in reactness

anyhoo this is the basic example of what I have as a template as its evolving have no clue if its correct

On top of that, react docs mention useRef should be used sparingly but to do anything complex requires like most all of my objects have this template of sorts

function App() {
  const exampleRef = useRef();
  
  useFrame((state, delta) => {
    exampleRef.current.rotation.x += delta;
  });
  
  return (
    <ExampleItem ref={exampleRef} />
  )
}

// in this example we need 2 refs
// one for internal so we can do animation stuff
// and the forwardref type so the parent component can work with it
// 
// React internal does not allow array refs
// but does have an arcane useImperativeHandle
// which then does more and we are forced to put the functions into it
// it makes for some interesting new way to closure methods, but as per example
// its the only solution to the 2+ ref issue

function ExampleItem(props, ref) {


    const datas = {
      thisRef : useRef(),
      modelRef : useRef()
    }
    
    useImperativeHandle(ref, () => {
      return {
        get mainObject() {
          return datas.thisRef.current;
        }
      };
    }, []);
    
    useFrame((state, delta) => {
      datas.thisRef.rotation.y += 0.1;
    });
    
    
    useEffect(()=>{
    }, []);
    
    function onCollide(other){
      console.log("other", other);
    }
    
    return (
      <PhysicsWrapper {...props} ref={datas.thisRef} onCollide={onCollide}>
        <ImportedModel ref={datas.modelRef} />
      </PhysicsWrapper>
    );
}

export default forwardRef(ExampleItem);
@tripdragon
Copy link
Author

tripdragon commented Dec 12, 2023

OK I worked it down a bit BUT its a SUPER UNKNOWN what does it break fix
I force the in ref to point directly to the internal useRef instead of sending it to the render element
so I can have access to the internal ref as I see fit
This in testing shows me both axis rotating!!
Wut does it break in react that I dont know about!?!?!?

I can survive one extra namespace wutRefObj222.pointerLike.current
Cause I know exactly what and where its coming from in this case

function App() {
  const wutRefObj = useRef();
  
  useFrame((_, delta) => {
    if(wutRefObj){
      wutRefObj.pointerLike.current.rotation.x += delta;
    }
  });
  
  return (
    <WutIsThis ref={wutRefObj} position={[-4, 0.4, 0]} scale={[2,1,1]} />
  )
}





// this here, we could extend the base classes like normal
// with logics without having to spam the react component
// and with the hacky ref= below we can access this!!
class Wut extends Object3D{
  isWut = true;
  constructor(){
    super();
  }
  tacos(){
    console.log("tacos", this.position);
  }
}

extend({ Wut })



function WutIsThis(props, ref) {
    const datas = {
      thisRef : useRef(),
    }
    // debugger
    // ok so here we try ref =
    // will never get the ref
    // ref = datas.thisRef;
    
    // but here if we point .current we get
    // ref.current.current.position !!!
    // so to better name the namespace we try adding a different name
    ref.current = datas.thisRef;
    ref.pointerLike = datas.thisRef;
    
    
    useFrame((state, delta) => {
      datas.thisRef.current.rotation.y += delta;
    });

    return (
      <wut ref={datas.thisRef} {...props}>
        <mesh>
            <sphereGeometry args={[1, 12, 12]} />
            <meshStandardMaterial color={'blue'} />
        </mesh>
      </wut>
        
    );
}

export default forwardRef(WutIsThis);

@tripdragon
Copy link
Author

tripdragon commented Dec 12, 2023

just to finish this for what I know.
The docs and mulling around some blogs explaining the possible source code state .current is fine to assign! BUT!
Only NOT in render... So i save the ref and then assign in useEffect
Now I can in main
wutRefObj222.current.rotation.x += delta;
And it works!

function WutIsThis222(props, ref) {
    const datas = {
      thisRef : useRef(),
      tempRef : ref
    }
    
    useFrame((state, delta) => {
      datas.thisRef.current.rotation.y += delta;
    });

    useEffect(() => {
      datas.tempRef.current = datas.thisRef.current;
    });
    
    return (
      <wut ref={datas.thisRef} {...props}>
        <mesh receiveShadow castShadow  >
            <sphereGeometry args={[1, 12, 12]} />
            <meshStandardMaterial color={'blue'} />
        </mesh>
      </wut>
        
    );
}

export default forwardRef(WutIsThis222);

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

No branches or pull requests

1 participant