Comments (14)
What's the problem using the default slot
If you're responding to me, then please see my earlier comment.
We can also add some logic to render children when camera and renderer there and provide just the camera and renderer without refs.
I don't think it's a bad idea, but it has much bigger implications than this DX issue.
I'd like to let the team have a chance to discuss this in a broader context, so I've opened a new discussion about the core and mentioned you there. #578 I've laid out what I think are the related open issues, including this one.
from tres.
Is this a duplicate of #573 ? If so, can we close there?
Edit: Closed #573.
from tres.
it is duplicated, #573 has the hack (can be closed)
from tres.
Are we talking about simply getting e.g., the renderer? Or also setting?
from tres.
it is only about using the context via default slot props, rn the example is not working since state
is undefined, cannot use useTresContext
since it can be only used via custom TresCanvas sfc children. Check linked issue and the hack in #573
from tres.
it is only about using the context
So it's only for getting, right?
from tres.
Yes (like inject or exposed context prop)
from tres.
Can we use defineExpose
instead?
We're using defineExpose
for this sort of thing in Cientos and Tres most other places. Is there a reason it won't work here?
I do think it would be a welcome improvement to simplify the current TresCanvas' context defineExpose
for v4 so that accessing the useful bits doesn't require a Demeter violation.
Any thoughts/opinions on using and simplifying defineExpose
here?
<slot>
Since we're not setting, only getting, I'm not sure about using the slot as suggested.
We have learned that components can accept props, which can be JavaScript values of any type. But how about template content? In some cases, we may want to pass a template fragment to a child component, and let the child component render the fragment within its own template.
But we're not passing info to a child here, so it feels like a mismatch to use a <slot>
to me.
from tres.
Rn context is exposed via defineExpose
, check the hack, maybe we only need to update the code snippet.
from tres.
About the default slot: the problem is the custom renderer, it is adding custom stuff in the default slot, I will ask Kevin if we can retarget the slot using custom setup component when using the custom renderer.
from tres.
@alvarosabu @andretchen0 using default slot props in ExtendExample:
from tres.
Here the changes, update TresCanvas.vue in root and run build script from root, then start docs dev server once ExtendExample.vue and extending.md files updated:
src/components/TresCanvas.vue
// L84
const slots = defineSlots<{
default(context: TresContext): any
}>()
const instance = getCurrentInstance()?.appContext.app
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' && ctx?.app) {
registerTresDevtools(ctx.app, context)
}
return () => h(Fragment, null, slots?.default ? slots.default(context) : [])
},
})
docs/.vitepress/theme/components/ExtendExample.vue
<script setup lang="ts">
import { TresCanvas, extend } from '@tresjs/core'
import { OrbitControls } from 'three/addons/controls/OrbitControls'
import { TextGeometry } from 'three/addons/geometries/TextGeometry'
// Add the element to the catalogue
extend({ TextGeometry, OrbitControls })
// import { useTresContext } from '@tresjs/core'
const styles = {
width: '100%',
height: '550px',
border: '1px solid #e2e2e2',
borderRadius: '8px',
overflow: 'hidden',
}
// const { camera, renderer } = useTresContext()
</script>
<template>
<ClientOnly>
<TresCanvas
v-slot="{ camera, renderer }"
shadows
xwindow-size
clear-color="#fff"
:style="styles"
>
<TresPerspectiveCamera :position="[0, 2, 4]" />
<TresScene>
<TresOrbitControls
v-if="camera.value && renderer.value"
:args="[camera.value, renderer.value.domElement]"
/>
<TresDirectionalLight
:position="[0, 2, 4]"
:intensity="2"
cast-shadow
/>
<TresMesh :rotation="[-Math.PI / 4, -Math.PI / 4, Math.PI / 4]">
<TresTorusGeometry :args="[1, 0.5, 16, 32]" />
<TresMeshToonMaterial color="#FBB03B" />
</TresMesh>
</TresScene>
</TresCanvas>
</ClientOnly>
</template>
docs/advanced/extending.md
# L36
<ClientOnly>
<div style="aspect-ratio: 16/9; height: auto; margin: 2rem 0; border-radius: 8px; overflow:hidden;">
<ExtendExample />
</div>
</ClientOnly>
from tres.
Hey @alvarosabu @userquin !
Rn context is exposed via defineExpose, check the hack
Sorry, I wasn't clear earlier.
I know that Tres is currently using defineExpose
to make context
available. I was wondering if cleaning up context
and continuing to use defineExpose
would be an acceptable alternative here.
That would be my preference.
Rationale
The example of bad DX from #573 is indeed a bummer:
<script setup>
// [...]
const trescanvas = ref();
const state = ref();
onMounted(() => {
setTimeout(() => {
state.value = trescanvas.value?.context;
}, 0);
});
// [...]
</script>
<template>
<TresCanvas ref="trescanvas" shadows alpha>
<TresPerspectiveCamera :position="[5, 5, 5]" />
<TresOrbitControls
v-if="state?.renderer"
:args="[state?.camera, state?.renderer?.domElement]"
/>
<!-- -->
</TresCanvas>
</template>
But as far as I can see, it can be rewritten more simply and cover the presented use case. See below.
It seems to me that the code below isn't materially different from the bad DX example. It only needs one extra line in <script setup>
– a ref
. It works with the current main
branch of Tres. (Edit: It doesn't allow destructuring as written though.)
(Fwiw, extend
in the latest release is throwing errors for me, so I can't recreate the bad DX example as written, but I've tried to recreate the salient parts without extend
below.)
<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import { ref } from 'vue'
// NOTE: TS likes to know the "shape" or the editor will complain.
const r = ref({ context: { renderer: { value: null } } })
</script>
<template>
<div style="height:50%">
<TresCanvas ref="r" clear-color="#82DBC5">
<TresMesh>
<TresBoxGeometry :args="[1, 1, 1]" />
<TresMeshNormalMaterial />
</TresMesh>
</TresCanvas>
</div>
<div>
<div v-if="r.context.renderer.value">
We have a renderer: {{ Object.keys(r.context.renderer.value) }}
</div>
<div v-else>
We don't have a renderer.
</div>
</div>
</template>
Preference: defineExpose
If I've understood the issue here correctly and if it's true that we can reduce the bad DX example to one extra line of code, my preference would be to stick with defineExpose
and reserve <slot>
s for use cases as defined in the Vue docs, e.g., we have a template fragment to send to a child for rendering.
Maybe we could smooth out what's defineExpose
d for v4 so that we can e.g., just use r.renderer
in the code above.
Moving forward
I don't want to impede forward progress. If I've misunderstood something here, please let me know. Otherwise, @alvarosabu , I'll leave the final call up to you.
from tres.
What's the problem using the default slot and exposing props? We can also add some logic to render children when camera and renderer there and provide just the camera and renderer without refs.
from tres.
Related Issues (20)
- Helpers diposal error since latest threejs update HOT 1
- LocalClippingEnabled HOT 1
- `useLoop` callback state missing controls HOT 1
- Render mode policies
- camera-position bug since version 3.8 HOT 3
- Add userData to vue devtools component inspector
- Invalid watch source error when declaring a CatmullRomCurve3 HOT 1
- position type is incorrect
- The Lifecycle Hooks is out of order after v3.9.0 HOT 8
- `<primitive> :object` breaking references to THREE objects HOT 1
- Physics support integration! HOT 3
- Toggle v-if on a Tres component declared in a separate SFC makes it detach from its parent HOT 9
- V4 drops fps HOT 2
- v4.0.1 The `onPointerLeave` function is not activating. HOT 8
- Manual rendering (edge case): canvases loaded into new tabs are initially blank
- Cannot read properties of undefined (reading 'dispose') - GridHelper HOT 6
- `Camera` wrapped by `TresGroup` cannot be used properly after `version 4.0` HOT 2
- `Event` is not triggered in `TresGroup` HOT 2
- Impossible to `inject` variable in canvas child component HOT 5
- intersect only objects with events registered HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from tres.