我认为问题在于它react-odometerjs
动态加载库,所以第一次Home
渲染组件时,库还没有加载。所以它渲染了仅显示 0loading
的选项组件。dynamic
因为它是您useEffect
运行的第一个渲染并且设置odometerValue
为 300。
稍后,react-odometerjs
库被加载,导致Home
重新渲染。Home 渲染Odometer
组件,但现在它渲染的是真实Odometer
组件而不是loading
组件,因此它会像里程表一样渲染,但第一次加载的值设置为 300,所以它只是位于 300。
如果您在将其设置为 300 之前添加一点延迟,那么您可以看到它正在工作。这是一个例子:
export default function Home() {
const [odometerValue, setOdometerValue] = useState(0);
useEffect(() => {
setTimeout(() => {
setOdometerValue(300);
}, 1000);
}, []);
return (
<Odometer
value={odometerValue}
format="(,ddd)"
theme="default"
/>
);
}
为此使用计时器的问题在于,库实际加载可能需要不同的时间。您需要使用加载此库的原因dynamic
是因为您正在使用 nextjs 并且它正在执行服务器端渲染(SSR),并且当它执行 SSR 时,它在 nodejs 中渲染,它没有定义document
或window
全局变量并odometer.js
使用它们。
所以你有一些选择:
- 如果库加载缓慢,请使用该
setTimeout
东西并获得一些令人讨厌的行为。
- 使用另一个库来获得里程表效果。
- fork 里程表库并删除它对 and 的依赖
document
,window
然后你可以使用import {Odometer} from 'react-odometerjs'
而不是使用dynamic
.
- 实现一些东西来让您知道库何时在客户端加载,以便您可以在库加载后设置初始值。我在下面放了一个hacky版本。
在设置之前等待库加载的 Hacky 版本odometerValue
:
let loadedCallback = null;
let loaded = false;
const Odometer = dynamic(async () => {
const mod = await import("react-odometerjs");
loaded = true;
if (loadedCallback != null) {
loadedCallback();
}
return mod;
}, {
ssr: false,
loading: () => 0
});
export default function Home() {
const [odometerLoaded, setOdometerLoaded] = useState(loaded);
const [odometerValue, setOdometerValue] = useState(0);
loadedCallback = () => {
setOdometerLoaded(true);
};
useEffect(() => {
if (odometerLoaded) {
setOdometerValue(1);
}
}, [odometerLoaded]);
useEffect(() => {
setOdometerValue(300);
}, [odometerValue]);
return (
<Odometer
value={odometerValue}
format="(,ddd)"
theme="default"
/>
);
}