【问题标题】:does setInterval inside a useEffect can recognize an updated state?useEffect 中的 setInterval 是否可以识别更新的状态?
【发布时间】:2021-06-03 14:43:44
【问题描述】:

我正在开发一个每隔 X 秒需要一个用户位置的应用。当组件被挂载时,间隔开始并获取 GPS 位置并将其与保存在组件状态中的旧位置进行比较。

问题是,间隔仅与变量的默认状态进行比较,因此如果新值与旧值不同,则会调用 setter 来更改该值。 我在位置 var 上使用了 useEffect,所以每当它发生变化时,只需打印它,它就会按新值正确执行。

但间隔继续使用 useState 挂钩中给出的默认值。

我在这里缺少什么。 我的代码示例如下:

 const [currentLocation, setCurrentLocation] = useState(null);
 let locationInterval = null;

useEffect(() => {
      locationInterval = setInterval(async () => {
        console.log("IN INTERVAL");
        navigator.geolocation.getCurrentPosition((location, error) => {
          if (location) {
            location = [location.coords.latitude, location.coords.longitude];

         /// currentLocation is not updating here for some reason

            if (JSON.stringify(location) !== JSON.stringify(currentLocation)) {
              alert(
                `the new location in interval ${location} old location: ${currentLocation}`
              );
              setCurrentLocation(location);
            }
          } else {
            console.log(error);
          }
        });
      }, 15000);
  }, [map]);

  useEffect(() => {
    return () => {
      clearInterval(locationInterval);
    };
  }, []);
  useEffect(() => {
/// currentLocation is updated here from the setInterval
    console.log("newlocation", currentLocation);
  }, [currentLocation]);

【问题讨论】:

  • 您似乎错过了要分享的代码的前几行。 setInterval 是否也在 useEffect 中?
  • 是的,修复了帖子。
  • 我刚刚回答了你的问题,但另一方面,需要提到你的代码中还有其他问题......比如你清除间隔的方法不正确。
  • 能不能去掉原生的alert方法,原生的alert会阻塞js的执行。改用控制台怎么样。

标签: reactjs react-hooks gps state intervals


【解决方案1】:

原因是因为currentLocation的值没有作为useEffect中的依赖项给出,因此useEffect回调函数只能访问原始的useState值。

请问在您运行 React 应用程序的终端上是否有任何 React 警告? 类似的东西

React Hook useEffect has a missing dependency: 'currentLocation'

但是在侧节点上,如果您将 currentLocation 添加到依赖项中,因为您正在更新 currentLocation 在您的 useEffect 中并且如果它被更新,它将再次重新运行 useEffect 回调。

【讨论】:

  • 嗨,首先感谢您的回答,我看到您说我的 clearInterval 有问题...清除工作正常..问题是我已将 currentLocation 的依赖项添加为你说过,但仍然在 setInterval 内部它是未定义的(在 setInterval 之外但在 useEffect 内部它被识别)
  • 我会这样做codesandbox.io/s/geolocation-timer-mc8wx?file=/src/App.js 如果没有重新渲染 currentLocation 状态,您可以检查计时器滴答日期是否卡住。如果 currentLocation 有重新渲染,useCallback 函数再次设置,useEffect 也是新的。
  • 如果将 currentLocation 添加为依赖项,它将在每次设置当前位置时创建新的 setInterval。这就是我推荐使用 useRef 的原因。我在下面回答了。
  • 张有很多方法可以做到这一点,包括您推荐的方法 useRef 但回答了 OP 的问题 does setInterval inside a useEffect can recognize an updated state? ,我创建了一个沙箱,答案是 yes,useEffect 中的 setInterval 可以识别更新的状态,但需要注意依赖数组。
【解决方案2】:

您无法在setInterval 中获取更新状态,因为useEffect 挂钩内的回调仅在其依赖数组更新时调用([map])。 当它被调用时,currentLocation 作为参数传递给 setInterval 的回调。这是useState当时的默认值。

为了防止这种情况,您可以这样做。

const [currentLocationRef] = useRef(null);
useEffect(() => {
  locationInterval = setInterval(async () => {
    //....
    if (JSON.stringify(location) !== JSON.stringify(currentLocationRef.current)) {
      currentLocationRef.current = location;
    }
  }, 15000);
  return () => {
    clearInterval(locationInterval);
  };
}, [map, currentLocationRef]);

此外,您应该在同一 useEffect 回调中返回 clearInterval。

这背后的原因是currentLocationRef.currentcurrentLocation 不同。第一个是 getter 函数,第二个是 value。这就是为什么第一个仍然能够访问更新的值,而第二个不能。

【讨论】:

    猜你喜欢
    • 2022-01-24
    • 2021-07-14
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 2022-11-03
    • 2022-07-08
    • 1970-01-01
    相关资源
    最近更新 更多