首页 > 解决方案 > Redux 状态未在 requestAnimationFrame 中更新

问题描述

当更新 Redux 状态时,更新后的状态是在组件中接收到的,而不是在requestAnimationFrame函数内。

即我们可以在组件声明顶部附近注销更新的状态(backgroundMode) - 更新按预期记录:

const VideoCanvas = ({ videoRef }: IVideoCanvasProps) => {
  ...
  console.log("backgroundMode", backgroundMode);
  ...

但在 requestAnimationFrame 函数中,None每帧只注销初始值 ( )。

  async function animate() {
    ...

    // Does not receive updates from Redux store
    console.log("animate backgroundMode", backgroundMode);
    
    ...

    animationFrame.current = requestAnimationFrame(animate);

控制台输出如下所示:

backgroundMode None
(20) VideoCanvas.tsx:71 animate backgroundMode None

// change dropdown to blur mode
VideoCanvas.tsx:26 backgroundMode Blur
(23) VideoCanvas.tsx:71 animate backgroundMode None

// change dropdown to mask mode
VideoCanvas.tsx:26 backgroundMode Mask
(62) VideoCanvas.tsx:71 animate backgroundMode None

添加backgroundMode到 useEffect 启动动画的依赖项中,只会产生两个动画线程,使问题更加严重。就目前而言,这种效果看起来像:

  useEffect(() => {
    animationFrame.current = requestAnimationFrame(animate);
    return () => {
      if (animationFrame.current) {
        cancelAnimationFrame(animationFrame.current);
      }
    };
  }, [bodyPixNet]);

有问题的文件可以在我的 GitHub 上完整查看

我们欢迎所有的建议!

标签: reactjsreact-hooksrequestanimationframe

解决方案


这种听起来像是animate函数中发生的旧的“陈旧状态外壳”问题。由于您是从动画开始的渲染周期递归调用requestAnimationFrame和传递的值animate,因此您可能希望backgroundMode在 ref 中也缓存一个副本,以便它可以随时更新,并且可以随时读取当前值。使用useEffect挂钩来更新缓存。

const backgroundModeRef = React.useRef(backgroundMode);

React.useEffect(() => {
  backgroundModeRef.current = backgroundMode;
}, [backgroundMode]);

animate函数中,引用缓存的 ref 值。

async function animate() {
  ...

  // Does not receive updates from Redux store
  console.log("animate backgroundMode", backgroundModeRef.current);

  ...

  animationFrame.current = requestAnimationFrame(animate);

推荐阅读