pmndrs / react-three-fiber

🇨🇭 A React renderer for Three.js
https://docs.pmnd.rs/react-three-fiber
MIT License
27.38k stars 1.57k forks source link

Custom values with `setDpr` are overridden with `dpr` prop on rerender #3099

Open nhtoby311 opened 11 months ago

nhtoby311 commented 11 months ago

I'm trying to create a component, that can setDpr, based on current graphics settings. I copied the implementation from AdaptiveDpr in drei. I noticed that when using this in an app, which of course, have multiple states update (unrelated to this component), the switching Dpr became not consistent, as sometimes it does not apply any thing but it should be. This happened clearly on route changes.

I have created a codesandbox for this: https://codesandbox.io/p/devbox/setdpr-issue-with-state-changes-4643zz?file=%2Fpages%2F_app.tsx%3A12%2C1 - it's Next.js

GraphicSettings on leva will controls how low dpr it is, which is in the Downscale.tsx. To see clearly the issue, changes the route at top left corner to go between Home and About. Swap couple of few times and there will be the inconsistent bug as the downscaled dpr is not applied. This doesn't seem to happened if I comment out the frequent state update at _app.tsx

I attached the video below to be clearer.

https://github.com/pmndrs/react-three-fiber/assets/52330522/c599f251-aeb1-4840-9a36-7ead9c3a9acc

acorn1010 commented 4 months ago

This also seems to happen if the canvas size changes, resetting the custom dpr from setDpr.

Here's how I got around it. This isn't perfect (the dpr will momentarily reset when resized), but it's a simple fix:

const setDpr = useThree((state) => state.setDpr);
const size = useThree((state) => state.size);

// Set adaptive pixelratio. We must listen on `size` change here because the dpr resets any time
// the canvas size changes.
useEffect(() => {
  setDpr(dpr);
}, [dpr, setDpr, size]);