我正在尝试在Next.js中进行页面转换。由于转换速度慢于页面加载速度,我需要计算动画完成所需的时间。转换应至少持续2秒,加载屏幕的淡入时间为1s,加载屏幕停留一点时间为500ms,退出时间为500ms。
实际上,我正试图使用new Date.getTime()
来实现这一点,并获取动画开始后经过的时间。
我尝试使用以下代码来检查代码是否正确:
function testDateValues() {
var startTime = new Date().getTime();
var animDuration = 1500; // In milliseconds
setTimeout(() => {
console.log(animDuration - (new Date().getTime() - startTime));
}, 1000);
}
此功能打印1秒后丢失的时间,即500ms(打印498-502之间的数字,但它是正确的(。
然而,当我将此代码转换为Next.js时,我会得到像-19604
、-60418
这样的数字,以及与剩余动画时间无关的数字。
代码如下(减少(:
import { useRouter } from 'next/router';
import { useState } from 'react';
export default function LoadingScreen() {
const router = useRouter();
const [loading, setLoading] = useState(false);
const [loadingStartTime, setLoadingStartTime] = useState(new Date().getTime());
useEffect(() => {
const handleStart = () => {
console.log("Loading started");
setLoading(true);
setLoadingStartTime(new Date().getTime());
};
const handleComplete = () => {
console.log("Loading completed");
console.log(1500 - (new Date().getTime() - loadingStartTime));
setTimeout(() => {
setLoading(false);
}, 1500 - (new Date().getTime() - loadingStartTime));
};
router.events.on("routeChangeStart", handleStart);
router.events.on("routeChangeComplete", handleComplete);
router.events.on("routeChangeError", handleComplete);
return () => {
router.events.off("routeChangeStart", handleStart);
router.events.off("routeChangeComplete", handleComplete);
router.events.off("routeChangeError", handleComplete);
};
}, []);
return {loading && (<div>Loading</div>)}
}
加载屏幕在components/layout.jsx
文件中。
import LoadingScreen from "./LoadingScreen";
export default function Layout({ children }) {
return (
<>
<motion.main>{children}</motion.main>
<LoadingScreen />
</>
)
}
加载屏幕甚至有一段时间没有显示。没有页面转换。
为什么几乎相同的代码返回的值如此不同?(为什么是-19604而不是500?(
您的问题是loadingStartTime
是在组件加载时初始化的,而该常数值就是效果中的代码将使用的值。setLoadingStartTime
调用对const
上的闭合值没有影响,它所做的只是导致组件重新渲染。但是,这不会导致效果再次运行。
有多种方法可以解决这个问题:
-
不使用
loadingStartTime
的状态,而只是在效果处理程序范围中使用一个可变变量:export default function LoadingScreen() { const router = useRouter(); const [loading, setLoading] = useState(false); useEffect(() => { let loadingStartTime = Date.now(); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ const handleStart = () => { console.log("Loading started"); setLoading(true); loadingStartTime = Date.now(); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ }; const handleComplete = () => { console.log("Loading completed"); console.log(1500 - (Date.now() - loadingStartTime)); setTimeout(() => { setLoading(false); }, 1500 - (Date.now() - loadingStartTime)); }; router.events.on("routeChangeStart", handleStart); router.events.on("routeChangeComplete", handleComplete); router.events.on("routeChangeError", handleComplete); return () => { router.events.off("routeChangeStart", handleStart); router.events.off("routeChangeComplete", handleComplete); router.events.off("routeChangeError", handleComplete); }; }, []); return {loading && (<div>Loading</div>)} }
-
不要为
loadingStartTime
使用状态,而是在转换开始时初始化的常数:export default function LoadingScreen() { const router = useRouter(); const [loading, setLoading] = useState(false); useEffect(() => { const handleStart = () => { console.log("Loading started"); setLoading(true); const loadingStartTime = Date.now(); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ const handleComplete = () => { console.log("Loading completed"); console.log(1500 - (Date.now() - loadingStartTime)); setTimeout(() => { setLoading(false); }, 1500 - (Date.now() - loadingStartTime)); }; router.events.once("routeChangeComplete", handleComplete); router.events.once("routeChangeError", handleComplete); }; router.events.on("routeChangeStart", handleStart); return () => { router.events.off("routeChangeStart", handleStart); }; }, []); return {loading && (<div>Loading</div>)} }
请注意,即使在组件卸载后,这也会保留完整和错误处理程序,这可能是可取的,也可能不是可取的,或者根本不重要。
-
使用两种具有适当依赖性的独立效果:
export default function LoadingScreen() { const router = useRouter(); const [loading, setLoading] = useState(false); const [loadingStartTime, setLoadingStartTime] = useState(Date.now()); useEffect(() => { const handleStart = () => { console.log("Loading started"); setLoading(true); setLoadingStartTime(Date.now()); }; router.events.on("routeChangeStart", handleStart); return () => { router.events.off("routeChangeStart", handleStart); }; }, []); useEffect(() => { // ^^^^^^^^^ console.log("New loadingStartTime", Date(loadingStartTime)); const handleComplete = () => { console.log("Loading completed"); console.log(1500 - (Date.now() - loadingStartTime)); setTimeout(() => { setLoading(false); }, 1500 - (Date.now() - loadingStartTime)); }; router.events.on("routeChangeComplete", handleComplete); router.events.on("routeChangeError", handleComplete); return () => { router.events.off("routeChangeComplete", handleComplete); router.events.off("routeChangeError", handleComplete); }; }, [loadingStartTime]); // ^^^^^^^^^^^^^^^^ return {loading && (<div>Loading</div>)} }