0

很遗憾,经过 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

请看代码,谁能解决问题。这对我很有帮助。

4

1 回答 1

0

我认为问题在于它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 中渲染,它没有定义documentwindow全局变量并odometer.js使用它们。

所以你有一些选择:

  1. 如果库加载缓慢,请使用该setTimeout东西并获得一些令人讨厌的行为。
  2. 使用另一个库来获得里程表效果。
  3. fork 里程表库并删除它对 and 的依赖documentwindow然后你可以使用import {Odometer} from 'react-odometerjs'而不是使用dynamic.
  4. 实现一些东西来让您知道库何时在客户端加载,以便您可以在库加载后设置初始值。我在下面放了一个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"
    />
  );
}
于 2021-08-30T05:27:55.787 回答