使用 react 从 animationFrame 内部访问状态数组

Issue accessing state array from inside animationFrame with react

我正在尝试使用 animationFrame 更新滚动上的一些元素。我想添加一个缓动效果,所以我希望元素通过缓动值更新它们的位置。我认为最好的方法是将所有值存储在一个数组中并相应地更新它们。当安装每个元素时,我将它们发送到一个上下文元素,该元素将它们添加到状态值数组中。

我的问题是我无法从动画函数内部访问数组。它在动画功能之外可用,但在内部不可用。我假设动画在数组被填充之前开始,但我试图在块数组随 useEffect 更改时停止并重新启动动画但无济于事。

这是问题的代码和框 Example Of Issue

在沙盒中,您可以在 ScrollContainer 组件的 animate() 函数中看到我在控制台记录 blocks 数组,然后在该函数之后我记录相同的数组。当您滚动数组时,不会仅记录一个空数组的可用块。但是在此功能下正确记录了可用块。

const animate = () => {
  const diff = yScroll - yCurrent;
  const delta = Math.abs(diff) < 0.1 ? 0 : diff * ease;
  if (delta) {
    yCurrent += delta;
    yCurrent = parseFloat(yCurrent.toFixed(2));
    animationFrame = requestAnimationFrame(animate);
  } else {
    cancelAnimation();
  }
  console.log("Animating Blocks", blocks);
};

console.log("Available Blocks", blocks);

const addBlock = block => {
  setBlocks(prev => {
    return [...prev, block];
  });
};

这是我开始动画的方式

const startAnimation = () => {
  if (!animationFrame) {
    animationFrame = requestAnimationFrame(animate);
  }
};

useEffect(() => startAnimation(), []);

谢谢。

我试过你的例子。在我看来,问题出在 useEffect 上。如果您向它添加空依赖项,那么它只会在第一次渲染后运行一次。当阻止状态更新时会有第二次渲染,但对于 useEffect 只有第一个状态是可见的,因为它只运行一次并且它使用带有陈旧闭包的 startAnimation。此版本的startAnimation使用原始状态的第一个版本的动画。

如果您将块作为依赖项添加到 useEffect,您最初的问题就解决了。

  useEffect(() => {
    yScroll = window.scrollY || window.pageYOffset;
    yCurrent = yScroll;
    startAnimation();

    window.addEventListener("scroll", updateScroll);
    return () => {
      window.removeEventListener("scroll", updateScroll);
    };
  }, [blocks]);

我尝试添加动画,但对我来说很不稳定。我对您的最终解决方案很感兴趣。这是哑剧:https://codesandbox.io/s/scrolling-animation-frame-array-issue-d05wz

我使用更高级别的动画库,如 react-spring。你可以考虑使用这样的东西。我认为它更容易使用。

https://codesandbox.io/s/staging-water-sykyj