如何阻止旋转器在 React 中跳动

2025-06-07

如何阻止旋转器在 React 中跳动

有时,在 Web 应用中加载数据时,会出现这种瀑布式流程。首先,获取一些身份验证数据,然后获取一些用户数据,最后获取构建视图所需的数据。

这通常会导致不同的微调器在同一个位置呈现,从而导致以下用户体验:

看到那个旋转器每次文本改变时都会“跳”回起始位置吗?我讨厌这样!当然,一旦我们能用Suspense处理所有事情,这个问题可能就会消失——但在此之前,我很乐意为我们的客户解决这个问题。

发生这种“跳跃”是因为我们的 DOM 上安装了一个新的微调器,并且 CSS 动画重新开始了。

几周前,React Native DOM 作者Vincent Reimer发布了这个小演示:

我惊呆了!🤩 这真的可能吗?你怎么会这么做?

困惑地看了几分钟后,我开始琢磨如何实现这一点。结果发现,这其实是个很简单的技巧!

如何同步你的旋转器

旋转器的移动部分通常使用CSS 动画实现。至少我在上面的例子中就是这么做的。而且这个动画 API 非常强大。

animation-delay属性通常用于编排 CSS 动画,或者将它们一个接一个地交错播放(例如,先淡入,然后滑入到位)。但事实证明,它也可以用来倒回动画进度——只需传递负值即可!

因为我们知道旋转动画循环有多长,所以我们可以使用负值animation-delay在旋转器安装时将动画“移动”到正确的位置。

给定以下 CSS:

keyframe spin {
  to { transform: rotate(360deg); }
}
.spinner {
  animation: 1000ms infinite spin;
  animation-delay: var(--spinner-delay);
  /* visual spinner styles omitted */
}
Enter fullscreen mode Exit fullscreen mode

我们可以在微调器组件安装时设置动画延迟:

const Spinner = (props) => {
  const mountTime = React.useRef(Date.now()));
  const mountDelay = -(mountTime.current % 1000);

  return (
    <div 
      className="spinner" 
      aria-label="Please wait" 
      style={{ '--spinner-delay': `${mountDelay}ms` }}
    />
  );
};
Enter fullscreen mode Exit fullscreen mode

这里,我们使用 React 的useRef钩子来保存组件挂载的时间点Spinner。然后,我们计算“倒回”旋转动画所需的毫秒数,并将该值设为负值。

--spinner-delay最后,我们通过 style prop传递CSS 自定义属性。

结果如下:

请提供更多详细信息

如果你想一步步了解这里发生的事情?别担心,这里有。细节非常详细。🙈

const mountTime = React.useRef(Date.now()));
Enter fullscreen mode Exit fullscreen mode

该函数Date.now()返回自 1970 年 1 月 1 日以来的毫秒数(有关其原因的详细说明,请参阅此处)。我们将使用该数字作为动画加载时的基准。

这个React.useRef钩子允许你保存任意值而不触发重新渲染。它非常适合保存诸如“挂载时间”之类的数据。你可以查看文档来了解更多有关此功能的详细信息。

const mountDelay = -(mountTime.current % 1000);
Enter fullscreen mode Exit fullscreen mode

这个mountDelay常量是我们要“倒回”动画的实际毫秒数。该数值1000必须与动画运行的毫秒数匹配——因此,如果您的旋转器比本例中的旋转速度慢或快,则需要调整这个数值。

mountTime我们通过访问refcurrent的属性来获取计算出的值mountDelay。这就是 React ref 的结构。

我们使用模运算符%来计算动画距离结束还有多少毫秒。如果您不熟悉该%运算符,也没关系。如果熟悉1123 % 1000,则结果为 123。如果熟悉,则结果为 0。您可以点击此处15 % 15了解更多信息

最后,我们对该数字取负数,因为我们希望将负延迟值传递到该animation-delay属性中。

<div style={{ '--spinner-delay': `${mountDelay}ms` }} />
Enter fullscreen mode Exit fullscreen mode

你知道可以通过 prop 将 CSS 自定义属性(以前称为 CSS 变量)传递给你的类吗?是的,我也是!事实证明,这实际上是一种将动态值传递给 CSS 的巧妙技巧。请注意,我们在传递style毫秒值之前添加了后缀。ms

您可以在MDN上阅读有关自定义属性的更多信息

keyframe spin {
  to { transform: rotate(360deg); }
}
.spinner {
  animation: 1000ms infinite spin;
  animation-delay: var(--spinner-delay);
}
Enter fullscreen mode Exit fullscreen mode

在 CSS 中,我们通过属性指定动画animation,然后animation-delay单独指定值。你也可以在声明中这样做animation,但对我来说,这样更易​​读一些。

就是这样!

希望你能用这个技巧来提升你的旋转器,并与朋友们分享。感谢阅读👋

文章来源:https://dev.to/selbekk/how-to-stop-your-spinner-from-jumping-in-react-5cmp
PREV
用 9 行代码保存你的 React 状态
NEXT
如何学习 Java 编程:为什么应该学习以及从哪里开始