reactjs - useState 正在使用 react-three-fiber 冻结 useFrame 中的渲染流
问题描述
我正在将我在三个 js 中的一个项目移动到 react-three-fiber 并且我在渲染循环中遇到了一些问题。也许我不完全理解 useFrame 是如何工作的。
这是代码沙盒:
https://codesandbox.io/s/react-three-test-y0zrx?file=/src/Three.jsx:1824-1835
所以在这个项目中,我使用滚动来在 z 轴上移动相机,并在我们到达 z 位置的不同点时更改显示的年份。正如你所看到的,当我们达到这一点时,我们使用了一个 useState 设置函数,它改变了状态,但也会产生延迟并暂时停用渲染效果。
这是更改显示信息的渲染器函数(从位置开始的年份):
ThreeComponent.jsx
const getYear = cameraZ => parseInt(cameraZ / -10 + START_YEAR, 10);
const getRoundedYear = year => Math.round(year / 10) * 10;
const shouldDisplayYear = roundedYear => {
return (
roundedYear % 100 === 0 || (roundedYear > 1890 && roundedYear % 10 === 0)
);
};
function Renderer() {
const composer = useRef();
const { scene, gl, camera } = useThree();
useFrame(() => {
const roundedYear = getRoundedYear(getYear(camera.position.z));
if (shouldDisplayYear(roundedYear)) {
// The problem lies here
setDisplayedYear(roundedYear);
}
return composer?.current?.render();
}, 1);
return (
<effectComposer ref={composer} args={[gl]}>
<renderPass attachArray="passes" scene={scene} camera={camera} />
<bokehPass
attachArray="passes"
args={[
scene,
camera,
{
focus: 20.0,
aperture: 1.1 * 0.00008,
maxblur: 0.05,
width: window.innerWidth,
height: window.innerHeight
}
]}
/>
</effectComposer>
);
}
...
return (
<div className="three-component" ref={canvasRef}>
<Canvas
...>
...
<Renderer/>
</Canvas>
</div>
);
set 函数是从父组件传递的,但如果它在同一个组件上,它会遇到同样的问题:
ThreeComponent.jsx
const ThreeComponent = ({ setDisplayedYear, startYear }) => {
App.js(父)
const [displayedYear, setDisplayedYear] = useState(START_YEAR);
有人可以解释为什么会发生这种滞后吗?或者也许有更好的方法来移动相机,只需要滚动和更新数字。
太感谢了!
解决方案
useFrame 是一个渲染循环,它每秒运行 60 次,你不能在其中产生副作用。setDisplayedYear 将要求 react 完成所有繁重的工作、差异化、通过 vdom 等。它充其量只会降低性能,或者它只会杀死标签。
你可以在这里做很多事情,最好的办法是在那时和那里改变相机。你从 useState(state => state.camera. 我会删除所有 setState 的东西。
编辑:
我认为您还在每次渲染时都在其中不必要地重新创建了许多对象。例如,每次 setState 更改时都会创建函数 Renderer(),它从头开始重新创建整个效果。组件应始终是固定引用。
这是一个进出相机的示例:https ://codesandbox.io/s/r3f-lod-rzuj1
这是另一个可能更接近您需要的东西(凸轮对滚动偏移做出反应):https ://codesandbox.io/s/adoring-feather-nk16u
推荐阅读
- javascript - 如何使用 passport-azure-ad (/w vue-msal) 保护 Web API
- python - 计算每月滚动净推荐值
- ios - 快速更改导航栏颜色
- r - 如何以递增的方式拆分文本
- c# - 在 Web API 响应中添加 zip 文件作为内容,下载时文件大小加倍
- c - 结构内只有一个成员联合的目的
- spring-boot - 无法验证交互,Spock 将“_”(任何参数)解释为文字“_”
- python - 如何使用请求和 python 在本地机器打开的端口中显示所有信息
- java - Spring SFTP:无法重命名.writing文件
- sql-server - master.dbo.fn_varbintohexstr(HashBytes('MD5','text') 在 SparkSQL 中的替换