Tresjs / tres

Declarative ThreeJS using Vue Components
https://tresjs.org
MIT License
1.91k stars 85 forks source link

Impossible to `inject` variable in canvas child component #732

Open emavitta opened 3 weeks ago

emavitta commented 3 weeks ago

Describe the bug

I'm trying to inject a variable inside a component in a TresCanvas, but it's always undefined.

In the example i log the variable provided by the first component but in the SecondTresjs component, the variable is undefined

Am i doing something wrong? I cannot find anything in the docs about the context.

Reproduction

https://stackblitz.com/edit/vitejs-vite-gtrfxh?file=src%2Fcomponents%2FFirstTresjs.vue

Steps to reproduce

No response

System Info

No response

Used Package Manager

npm

Code of Conduct

JakobHock commented 3 weeks ago

I think the problem lies with the custom Tresjs renderer. I think it loses the previous context from the default renderer.

The first time you inject it's actually outside the TresJS renderer thus still having access to the same context and there for the provided value. The second time you inject the context has changed and the dependency injection does not have any value registered for the key test.

Notice if you inject a value in SecondTresjs.vue and add a child like ThirdTresjs.vue the provided value is correctly injected like in this Example.

Take the explanation with a grain of salt as i'm not 100% sure about the specfics.

andretchen0 commented 3 weeks ago

Fwiw, if anyone would like to look into this, here's a slightly more minimal reproduction with some notes and a minimal on-screen test:

https://stackblitz.com/edit/vitejs-vite-5q8vs7?file=src%2FApp.vue

emavitta commented 3 weeks ago

I think the problem lies with the custom Tresjs renderer. I think it loses the previous context from the default renderer.

The first time you inject it's actually outside the TresJS renderer thus still having access to the same context and there for the provided value. The second time you inject the context has changed and the dependency injection does not have any value registered for the key test.

Notice if you inject a value in SecondTresjs.vue and add a child like ThirdTresjs.vue the provided value is correctly injected like in this Example.

Take the explanation with a grain of salt as i'm not 100% sure about the specfics.

thanks for the solution and the explanation, even though i cannot understand why you cannot have more than one context

emavitta commented 2 weeks ago

think the problem is in this function

const createInternalComponent = (context: TresContext) =>
  defineComponent({
    setup() {
      const ctx = getCurrentInstance()?.appContext;
      if (ctx) {
        ctx.app = instance as App;
      }
      provide("useTres", context);
      provide("extend", extend);
      if (typeof window !== "undefined") {
        registerTresDevtools(ctx?.app, context);
      }
      return () => h(Fragment, null, slots?.default ? slots.default() : []);
    },
  });

It could be possible to add an additional params (context: TresContext,additionalContext) to the function called inside mountCustomRenderer that pass custom provided variables. It can be an array given to a new props on the canvas (additional-context=['key-one','key-two']) ; this way inside mountCustomRender we can inject these variables, pass them to createInternalComponent() and from here provided again white the same name.