如何阻止旋转器在 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 */
}
我们可以在微调器组件安装时设置动画延迟:
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` }}
/>
);
};
这里,我们使用 React 的useRef
钩子来保存组件挂载的时间点Spinner
。然后,我们计算“倒回”旋转动画所需的毫秒数,并将该值设为负值。
--spinner-delay
最后,我们通过 style prop传递CSS 自定义属性。
结果如下:
请提供更多详细信息
如果你想一步步了解这里发生的事情?别担心,这里有。细节非常详细。🙈
const mountTime = React.useRef(Date.now()));
该函数Date.now()
返回自 1970 年 1 月 1 日以来的毫秒数(有关其原因的详细说明,请参阅此处)。我们将使用该数字作为动画加载时的基准。
这个React.useRef
钩子允许你保存任意值而不触发重新渲染。它非常适合保存诸如“挂载时间”之类的数据。你可以查看文档来了解更多有关此功能的详细信息。
const mountDelay = -(mountTime.current % 1000);
这个mountDelay
常量是我们要“倒回”动画的实际毫秒数。该数值1000
必须与动画运行的毫秒数匹配——因此,如果您的旋转器比本例中的旋转速度慢或快,则需要调整这个数值。
mountTime
我们通过访问refcurrent
的属性来获取计算出的值mountDelay
。这就是 React ref 的结构。
我们使用模运算符%
来计算动画距离结束还有多少毫秒。如果您不熟悉该%
运算符,也没关系。如果熟悉1123 % 1000
,则结果为 123。如果熟悉,则结果为 0。您可以点击此处15 % 15
了解更多信息。
最后,我们对该数字取负数,因为我们希望将负延迟值传递到该animation-delay
属性中。
<div style={{ '--spinner-delay': `${mountDelay}ms` }} />
你知道可以通过 prop 将 CSS 自定义属性(以前称为 CSS 变量)传递给你的类吗?是的,我也是!事实证明,这实际上是一种将动态值传递给 CSS 的巧妙技巧。请注意,我们在传递style
毫秒值之前添加了后缀。ms
您可以在MDN上阅读有关自定义属性的更多信息。
keyframe spin {
to { transform: rotate(360deg); }
}
.spinner {
animation: 1000ms infinite spin;
animation-delay: var(--spinner-delay);
}
在 CSS 中,我们通过属性指定动画animation
,然后animation-delay
单独指定值。你也可以在声明中这样做animation
,但对我来说,这样更易读一些。
就是这样!
希望你能用这个技巧来提升你的旋转器,并与朋友们分享。感谢阅读👋
文章来源:https://dev.to/selbekk/how-to-stop-your-spinner-from-jumping-in-react-5cmp