[solved] r3f: How to update plane scale to VideoTexture size after loading?

Hey, just getting started with react-three-fiber and I have issues understanding how the “data flows”. I have a plane and a VideoTexture, and want to update the plane size when the video was loaded. My r3f component looks like this:

export function VideoPlane(props) {

    const [width, setWidth] = useState(1);
    const map = useVideoTexture(props.src, { 
        onloadedmetadata: function() {
            console.log('new width', this.videoWidth / this.videoHeight);
            setWidth(this.videoHeight / this.videoWidth);

    return (
        <mesh scale={[width, 1, 1]}>
            <planeGeometry />
            <meshBasicMaterial map={map} />

I see the correct width log but console gives warning: Can’t perform a React state update on a component that hasn’t mounted yet. This indicates that you have a side-effect in your render function that asynchronously later calls tries to update the component. Move this work to useEffect instead.

I tried this a few different ways but always end up with the same errors. Any ideas? (I’m using drei useVideoTexture)

Okay this seems to work. I think react-suspend prevents VideoPlane from rendering until onloadedmetadata fires inside useVideoTexture, so I simply can read videoWidth and videoHeight. Feels like magic, i take it!

const videoTexture = useVideoTexture(props.src, {});
const width = videoTexture.source.data.videoWidth / videoTexture.source.data.videoHeight;

that’s how suspense works in general, yes. internally it actually throws, like an exception, passing the promise into reacts hands. react awaits it and continues rendering the component once it resolves. by then the result is there properties and all, no need for error checking etc.

ps, should you need it, there’s an aspect ratio css cover hook in drei: GitHub - pmndrs/drei: 🥉 useful helpers for react-three-fiber if you want to run it fullscreen

1 Like