Open drcmda opened 2 years ago
This works fine when using React.createElement
in development (there's current a hard-dependency on that to change opacity
to opacity.value
at runtime):
import * as React from 'react'
import * as ReactDOM from 'react-dom/client'
import { Canvas } from '@react-three/fiber'
import { signal } from '@preact/signals-react'
const opacity = signal(1)
setTimeout(() => (opacity.value = 0.5), 3000)
function Box() {
console.log('rerender')
return React.createElement(
'mesh',
null,
React.createElement('boxGeometry'),
React.createElement('meshBasicMaterial', { transparent: true, color: 'orange', opacity }),
)
}
ReactDOM.createRoot(window.root).render(React.createElement(Canvas, null, React.createElement(Box)))
I found some other issues that completely break the bindings with a fix in #130, but I don't believe they are directly related.
The reason this doesn't work is because we don't currently support fine-grained prop updates in the React integration. The Preact integration supports this because it injects fine-grained prop-to-DOM updates, but we cannot do that in React.
However, it is possible to implement VDOM-based fine-grained updates in a way that works nicely with react-three-fiber
as well as React-DOM. Here is a patch that makes this work: (just import anywhere)
import { Signal } from '@preact/signals-react'
import * as rt from 'react/jsx-runtime'
import * as React from 'react'
rt.jsx = wrap(rt.jsx)
rt.jsxs = wrap(rt.jsxs)
let createElement = React.createElement
React.createElement = wrap(createElement)
const wrappers = new Map()
function wrap(method) {
return function (type) {
if (typeof type === 'string') {
let t = wrappers.get(type)
if (!t) wrappers.set(type, (t = Wrapper.bind(null, type)))
arguments[0] = t
}
return method.apply(this, arguments)
}
}
function Wrapper(type, props) {
let p = {}
for (let i in props) {
let v = props[i]
p[i] = i !== 'children' && v instanceof Signal ? v.value : v
}
return createElement(type, p)
}
Here it is working with the original demo code unmodified: https://codesandbox.io/s/peaceful-brown-n1qjne?file=/src/App.js:91-121
codesandbox: https://codesandbox.io/s/interesting-panna-urdtu6?file=/src/App.js
it's not a div, but it would be fantastic if it could work.