4 ms·
Is there an error in the examples? You have const mesh = useRef() ... <mesh ref={mesh} ... You'll be rendering an undefined element (before the
by tills13 5y ago
Is there an error in the examples? You have
const mesh = useRef()
...
<mesh ref={mesh} ...
You'll be rendering an undefined element (before the ref has a chance to attach).
Also, the TypeScript example makes me head hurt.
const ref = useRef(null!)
Ah, yes. A non-null null literal.
- shallowthought 5y agoI have to wonder: Have we gone too far? Is TypeScript becoming more tedious than helpful? Has React lost its way in its blind zeal for pure functions? ...no, no, definitely not. Must've gone crazy for a second there.
- tills13 5y agoI think I blame JavaScript for this mess, not the other way around.
- CraftThatBlock 5y agoI'm guessing they are overloading the ref's usage with the custom renderer. I believe that a renderer can accept non-function/class components in theory, which is why this works. I don't really like this though, although interesting, it feels like a hack and might not integrate well with tooling (e.g. the Typescript example). How I would have implemented it was exposition a Mesh component which wraps this, and a useMesh hook to wrap and type the ref.
- yashap 5y agoYeah, I don’t have experience with this lib, but the example code looks overly magic. But I’m also more of a backend dev, and find the useRef API to be inherently confusing, so that’s probably part of it.
- mlsarecmg 5y agor3f is a custom renderer, there is no difference in useRef between a div or a mesh, refs give you the underlying object. lowercase elements are native elements (div, span, mesh, view, box), they are defined by the renderer. uppercase is for components.
- tills13 5y agoAh, if they're using a custom JSX Pragma it might make sense. Still a little too bespoke for me.
- mlsarecmg 5y agono special jsx pragma needed. this is actually just plain react, <div> <span> and so on come from react-dom, which defines these elements. other renderers define theirs. here's a mini custom renderer if this interests you: https://codesandbox.io/s/reurope-reconciler-hd16y https://codesandbox.io/s/reurope-reconciler-hd16y
- afloatboat 5y agoI believe the `null!` is some trickery to let the rest of the code know that the `ref.current` will never be null, but with how React works you can’t really provide any other value. It prevents having to check for `null` everytime you address the value. I don’t understand your first issue. The component is assigned to the ref, not the other way around, so why would it render `undefined`? It’s possible that `mesh.current` is undefined at first render, but that shouldn’t matter for the component, only for the reference.
- tills13 5y agoOops, I guess it's not undefined, but it'll attempt to render a ref object. const mesh = useRef() <mesh /> The underlying JavaScript (i.e. not JSX) on the first render , is React.createElement(mesh /* { current: undefined } */, { ref: mesh } ) In fact, I don't even think it matters which render you're talking about. It's still rendering a ref (again, { current: <undefined or a Three.MESH, I guess> }). That doesn't seem right to me.
- afloatboat 5y agoAh, right. But the mesh useRef is not wat is being rendered, the `mesh` component is more like rendering a div. If you open the sandbox and remove the useRef mesh and references it will still work. Pretty confusing though, would have been better to call it `meshRef`. I also expected these components to be capitalised, but it probably makes sense in the way that in the dom renderer default components are lowercase as well.
- tills13 5y agoyeah imo simply changing the variable name of the ref would go a long way, here.
- petrbela 5y agoActually, the compiled JS is `React.createElement('mesh', { ref: mesh } )`. JSX compiler converts all lower-case names to strings. Only upper-case name (and composites like `rn.View`) are converted to variables. The reason r3f uses lower-case names for built-in components is to distinguish them from your own components; from the documentation: "It merely expresses Three.js in JSX: <mesh /> becomes new THREE.Mesh(), and that happens dynamically." So whenever you see <mesh /> or anything else lower-case it is just an JSX alias for a Three.js core component. Note that they're not HTML tags in the resulting output; since they're rendered inside <Canvas />, they're transformed to Three.js automatically.
- mlsarecmg 5y agothis is how refs work. it's the same with a div. the ref will be filled in useEffect, not before. null! is a common typescript thing, it is a semantic guarantee that the ref is static and hence will be available. this saves you the if (ref.current) { ... } check.
- tills13 5y agoThe ref isn't used in an effect, though, at least not in the provided code.
- tills13 5y agoTo clarify, I'm not talking about the ref _prop_, I'm talking about them using the ref as the element.
- mlajtos 5y agoIt’s lowercase, so it will act as plain-old tag. If the name would be uppercase, that would be a bug you described.
- tills13 5y agohm, interesting. I didn't know that -- I knew about custom tags / variable tags but never knew it _required_ them to be PascalCased. I feel like if I saw code like this come from one of my team members I'd ask them to change the name of the ref.
- mlsarecmg 5y agono ref is used as an element in that code. const ref = useRef() useEffect(() => console.log(ref), []) return <div ref={ref} /> will return { current: [dom node] } const ref = useRef() useEffect(() => console.log(ref), []) return <mesh ref={ref} /> will return { current: [mesh node] }
- sswu 5y agoThe TypeScript example does feel a little weird. I've used this library successfully with React + TypeScript with the following pattern: const mesh = useRef<THREE.Mesh>(null); // mesh has type RefObject<THREE.Mesh | null> ... useFrame((): void => { if (mesh.current != null) { mesh.current.rotation.x += 0.01; } }); ... return <mesh ref={mesh} ... /> As others have mentioned, the ref will typically attach by the time a `useEffect` hook is called, but for safety it's nice to have the null check.
- onion2k 5y agoThe useRef hook doesn't return a ref. It returns a function for setting the ref value. The value is in ref.current. The ref prop calls the setter with a ref to the element on mount.
- lxe 5y agoI was scratching my head over this one too. Other answers in the thread don't seem right. I then realized this: const mesh = useRef(... assigns an instance of something (`React.mutableRefObject`) to a variable in scope, but <mesh ... after compiling into normal JavaScript and becomes (0, _jsxRuntime.jsxs)("mesh"... (see `console.log(__SANDBOX_DATA__.data.transpiledModules['/src/App.js:'].source.compiledCode) `) So that's why you're not seeing the editor or runtime complain about this. `<mesh` (lowercase), as with other lowercased react elements get translated into `Something('mesh'`, and doesn't require a defined component variable. Think this: const div = 'not a div -- i am a string' return <div>{div}</div> Just one of the many gotchas of many layers of JavaScript/TypeScript/React/etc... programming environments.
- strogonoff 5y agoI’d answer the original question… > Is there an error in the examples? You have const mesh = useRef() ... <mesh ref={mesh} ... > You'll be rendering an undefined element (before the ref has a chance to attach). …as follows: 1. On that last line, <mesh> is just a regular element[0]. 2. Ref assignment makes this element’s instance accessible within component code[1] under a constant, here coincidentally (and confusingly, I must say) named “mesh”. The constant could’ve been named anything else, like “el”, and the example would work exactly the same way: const el = useRef() ... <mesh ref={el} ... 3. How come the constant in the original example does not shadow the equivalently named built-in JSX element? Well, there is a convention/hard-coded rule in React/JSX/TSX where it simply would not resolve lowercase identifiers to custom components. If we change “mesh” to “Mesh” in the original example, then the app would attempt to use the ref constant as a (malformed) custom component, and predictably throw. [0] https://www.w3.org/TR/2016/CR-SVG2-20160915/shapes.html#MeshElement https://www.w3.org/TR/2016/CR-SVG2-20160915/shapes.html#Mesh... [1] https://reactjs.org/docs/refs-and-the-dom.html#refs-and-function-components https://reactjs.org/docs/refs-and-the-dom.html#refs-and-func...
- dalmo3 5y agoExcellent explanation, thank you!
- deleted 5y ago[deleted]