简体   繁体   English

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

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

I often encounter the situation that I build a window.requestAnimationFrame based render loop, but want some states to be exchanged with the inside of the loop.我经常遇到这样的情况,我构建了一个基于window.requestAnimationFrame的渲染循环,但是想要在循环内部交换一些状态。 There are a few ways to accommplish that, but I'm not sure which on is the best.有几种方法可以做到这一点,但我不确定哪种方法最好。 My setup usually looks something like this:我的设置通常是这样的:

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);
  }, []);
}

Note that using someState inside the loop will always use the value from the last ran of the effect, not necessarily the current value.请注意,在循环中使用someState将始终使用效果的最后一次运行的值,不一定是当前值。 Here are the some obvious solutions:以下是一些显而易见的解决方案:

  • I can put someState in the dependency array of useEffect , this way the loop will be restarted whenever the state changes.我可以将someState放在 useEffect 的依赖数组中,这样只要useEffect发生变化,循环就会重新启动。 But if the initialization is expensive, for example with WebGL where I create all the textures there and compile the shaders, it doesn't seem very elegant.但是如果初始化很昂贵,例如使用 WebGL,我在那里创建所有纹理并编译着色器,它似乎不是很优雅。

  • I can use two effects, one for the initialization of the loop itself, and another one for just the loop, which stops and starts on every state change.我可以使用两种效果,一种用于循环本身的初始化,另一种仅用于循环,它在每次 state 更改时停止和启动。 But I still think, ideally an animation loop should run until it stops and not stop/start in between.但我仍然认为,理想情况下,animation 循环应该一直运行到停止,而不是在其间停止/启动。

  • Another solution with two effects, but this time I do const someStateRef = useRef() and then create an effect with someState in its dependency array which just writes someState into someStateRef.current so I can use it inside the loop.另一个具有两种效果的解决方案,但这次我执行const someStateRef = useRef()然后在其依赖数组中使用someState创建一个效果,它只是将someState写入someStateRef.current因此我可以在循环中使用它。 Here is an example where I implement this.是我实现它的示例。 Alternatively one can write someState into someStateRef.current on every render, without another effect.或者,可以在每次渲染时将someState写入someStateRef.current ,而不会产生其他影响。 Looks very performant, but not really elegant.看起来非常高效,但不是很优雅。

What's the most React way to do it?最 React 的方式是什么?

I'd go with the 3rd option that you already implemented , as it looks exactly like one example from the React Hooks FAQ (3rd code block):我将 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
}

(replacing set/clearInterval with request/cancelAnimationFrame ) (将set/clearInterval替换为request/cancelAnimationFrame

For completeness: The first two options suffer from the flaws you mentioned, and writing someState to someStateRef.current on every render without another effect is not recommended.为了完整起见:前两个选项存在您提到的缺陷,不建议在每次渲染时将someStateRef.current写入someState而没有其他效果。

Avoid reading and updating refs during rendering because this makes your component's behavior difficult to predict and understand.避免在渲染期间读取和更新引用,因为这会使组件的行为难以预测和理解。

source 来源

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

相关问题 React - 如何在 useEffect 中更新 state 而不会导致无限循环? - React - How to update the state in useEffect without causing an infinite loop? 在儿童的第一次渲染 useEffect 上用旧状态反应钩子 useState - React hook useState with old state on children's first render useEffect React 在 onChange 函数中如何更新另一个自定义组件的状态并传入一个值? - In React when in onChange function how to update another custom component's state and pass a value in? React UseEffect 渲染无限循环 - React UseEffect render infinite loop 使用 useEffect 循环反应陈旧的 state - React stale state with useEffect loop 使用更新循环时如何在useEffect中获取更新状态 - How to get updated state in useEffect when using update loop 如何更新 state 但不触发无限 useEffect 循环? - How do I update state but not trigger the infinite useEffect loop? 如何防止 state 对反应 onClick function (外部 useEffect)的更新? - How to prevent a state update on a react onClick function (outside useEffect)? 如何使用 socket.io-client 在 useEffect 挂钩中更新 React state - How update React state in useEffect hooks with socket.io-client Next.js 仅在桌面上渲染视频:useEffect 无法对未安装的组件执行 React state 更新 - Next.js render video only on desktop: useEffect can't perform a React state update on an unmounted component
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM