繁体   English   中英

如何在 React 的 useEffect 中将 State 更新传递给自定义渲染循环?

[英]How To Pass State Update To Custom Render Loop In React's `useEffect`?

我经常遇到这样的情况,我构建了一个基于window.requestAnimationFrame的渲染循环,但是想要在循环内部交换一些状态。 有几种方法可以做到这一点,但我不确定哪种方法最好。 我的设置通常是这样的:

function Animation({someState}) {
  const loopDataRef = useRef();
  useEffect(() => {
    //do something initialization work for the renderloop, e.g. getContext, etc.
    let frame;
    const loop = (cts) => {
      frame = window.requestAnimationFrame(loop)
      //do some loop work using someState and loopDataRef.current
    }
    loop();
    return () => window.cancelAnimationFrame(frame);
  }, []);
}

请注意,在循环中使用someState将始终使用效果的最后一次运行的值,不一定是当前值。 以下是一些显而易见的解决方案:

  • 我可以将someState放在 useEffect 的依赖数组中,这样只要useEffect发生变化,循环就会重新启动。 但是如果初始化很昂贵,例如使用 WebGL,我在那里创建所有纹理并编译着色器,它似乎不是很优雅。

  • 我可以使用两种效果,一种用于循环本身的初始化,另一种仅用于循环,它在每次 state 更改时停止和启动。 但我仍然认为,理想情况下,animation 循环应该一直运行到停止,而不是在其间停止/启动。

  • 另一个具有两种效果的解决方案,但这次我执行const someStateRef = useRef()然后在其依赖数组中使用someState创建一个效果,它只是将someState写入someStateRef.current因此我可以在循环中使用它。 是我实现它的示例。 或者,可以在每次渲染时将someState写入someStateRef.current ,而不会产生其他影响。 看起来非常高效,但不是很优雅。

最 React 的方式是什么?

我将 go 与您已经实施的第三个选项,因为它看起来与 React Hooks FAQ(第三个代码块)中的一个示例完全一样:

function Example(props) {
  // Keep latest props in a ref.
  const latestProps = useRef(props);
  useEffect(() => {
    latestProps.current = props;
  });

  useEffect(() => {
    function tick() {
      // Read latest props at any time
      console.log(latestProps.current);
    }

    const id = setInterval(tick, 1000);
    return () => clearInterval(id);
  }, []); // This effect never re-runs
}

(将set/clearInterval替换为request/cancelAnimationFrame

为了完整起见:前两个选项存在您提到的缺陷,不建议在每次渲染时将someStateRef.current写入someState而没有其他效果。

避免在渲染期间读取和更新引用,因为这会使组件的行为难以预测和理解。

来源

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM