使用 eslint Exclusive-deps 响应订阅/取消订阅的 useEffect 依赖项

Ale*_*yne 2 javascript reactjs ionic-framework react-hooks

我有一个useEffect钩子,它应该在组件出现时订阅地理定位更新,然后在组件消失时取消订阅。所以我[]作为效果依赖传递,因为我只希望它在挂载/卸载时运行。

import { useWatchPosition } from "@ionic/react-hooks/geolocation"
import React, { useEffect } from "react"

function SiteMap() {
  const { currentPosition, startWatch, clearWatch } = useWatchPosition()

  // Subscribe/Unsubscribe to geo location on component mount/unmount.
  useEffect(() => {
    startWatch()
    return clearWatch
  }, [])

  return <svg>{/* ... */}</svg>
}
Run Code Online (Sandbox Code Playgroud)

这导致 eslint 发出警告:

React Hook useEffect 缺少依赖项:clearWatchstartWatch. 包括它们或删除依赖项array.eslint(react-hooks/exhaustive-deps)

所以我把它改成了这样:

  useEffect(() => {
    startWatch()
    return clearWatch
  }, [startWatch, clearWatch])
Run Code Online (Sandbox Code Playgroud)

这会导致无限渲染循环。

我猜无限循环是由@ionic/react-hooks/geolocation每次useWatchPosition()调用时都会创建新函数的库引起的,使依赖项看起来过时。

所以我应该通过以下方式禁用对这一行的检查:

// eslint-disable-next-line react-hooks/exhaustive-deps
Run Code Online (Sandbox Code Playgroud)

或者我有什么方法可以在这里做正确的事情?

Ori*_*ori 6

阅读useWatchPosition 源代码,你可以看到函数不是用 来创建的useCallback,这意味着只要调用钩子就会重新生成它们。

您可以在 a 中存储对函数的引用ref,并使用ref.current调用该函数:

function SiteMap() {
  const { currentPosition, startWatch, clearWatch } = useWatchPosition()
  
  const startWatchRef = useRef(startWatch)
  const clearWatchRef = useRef()

  useEffect(() => {
    clearWatch.current = clearWatch // the updated clearWatch
  })

  // Subscribe/Unsubscribe to geo location on component mount/unmount.
  useEffect(() => {
    startWatchRef.current()
            
    return () => clearWatchRef.current()
  }, [])

  return <svg>{/* ... */}</svg>
}
Run Code Online (Sandbox Code Playgroud)