如何在 Next js 中集成 React Odometerjs
How can I integrate React Odometerjs in Next js
非常遗憾,经过3天的尝试,我仍然无法将Odometer js集成到Next js中。我不明白我的代码哪里错了。这是我在 CodeSandBox 中的代码 - https://codesandbox.io/s/long-moon-z9zqu
这是代码-
export default function Home() {
const [odometerValue, setOdometerValue] = useState(0);
useEffect(() => {
setTimeout(() => {
setOdometerValue(300);
}, 1000);
}, []);
return (
<Odometer
value={odometerValue}
format="(,ddd)"
theme="default"
/>
);
}
我使用的 npm pacjage - https://www.npmjs.com/package/react-odometerjs
请看代码,谁能解决问题。对我很有帮助。
我认为问题在于它正在动态加载 react-odometerjs
库,因此第一次呈现 Home
组件时,尚未加载该库。所以它呈现 dynamic
选项的 loading
组件,它只显示一个 0。因为它是第一个呈现你的 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 时它在没有 document
的 nodejs 中呈现或 window
定义了全局变量并且 odometer.js
使用它们。
所以你有一些选择:
- 使用
setTimeout
东西,如果库加载缓慢,会出现一些稍微烦人的行为。
- 使用另一个库来获得里程表效果。
- 分叉里程计库并删除它对
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"
/>
);
}
非常遗憾,经过3天的尝试,我仍然无法将Odometer js集成到Next js中。我不明白我的代码哪里错了。这是我在 CodeSandBox 中的代码 - https://codesandbox.io/s/long-moon-z9zqu
这是代码-
export default function Home() {
const [odometerValue, setOdometerValue] = useState(0);
useEffect(() => {
setTimeout(() => {
setOdometerValue(300);
}, 1000);
}, []);
return (
<Odometer
value={odometerValue}
format="(,ddd)"
theme="default"
/>
);
}
我使用的 npm pacjage - https://www.npmjs.com/package/react-odometerjs
请看代码,谁能解决问题。对我很有帮助。
我认为问题在于它正在动态加载 react-odometerjs
库,因此第一次呈现 Home
组件时,尚未加载该库。所以它呈现 dynamic
选项的 loading
组件,它只显示一个 0。因为它是第一个呈现你的 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 时它在没有 document
的 nodejs 中呈现或 window
定义了全局变量并且 odometer.js
使用它们。
所以你有一些选择:
- 使用
setTimeout
东西,如果库加载缓慢,会出现一些稍微烦人的行为。 - 使用另一个库来获得里程表效果。
- 分叉里程计库并删除它对
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"
/>
);
}