React 的 useEffect 依赖数组是反模式吗

Is React's useEffect dependency array an anti pattern

我有一个关于 React 中的 useEffect 和依赖数组的问题。据我了解 useEffect 是用来处理状态变化的副作用的。

假设我正在创建一个像 Zoom 这样的应用程序。因此,对于接收方调用,当名为“callState”的本地状态变量等于应答时,我有代码处理 useEffect 中的调用请求:

  const [localStream, setLocalStream] = useState()
  const [remoteStream, setRemoteStream] = useState()
  const [remoteRequest, setRemoteRequest] = useState()
  const [currentUser, setCurrentUser] = useState()
  const [callState, setCallState] = useState()
  useEffect(() => {
        const answerCall = async () => {
            console.log("answering")
            if (!remoteRequest || callState !== CallState.Answering) return
            console.log('remoteStream', remoteStream)
            console.log('localStream', localStream)
            console.log('currentUser', currentUser)

            }
            answerCall()
         }, [localStream, remoteStream, remoteRequest, currentUser, callState])

这里的问题是我只想在 callState 更改时调用 answerCall useEffect,但它确实需要使用许多状态变量。我有条件 if (!remoteRequest || callState !== CallState.Answering) return 所以如果 callState 没有被回答我会阻止 运行ning 的 useEffect,但是我连续调用 useEffect 似乎很奇怪实际上只意味着 运行 当 callState发生变化,如果 localStream 等状态变量之一发生变化(例如,如果我将流更改为后置摄像头),我需要一个条件来提前退出。看起来这种设计很容易出错和错误,即使它更具声明性。

我添加了 console.log('answering') 来表明我的观点。如果用户登录,callState 设置为挂断,当前用户刷新属性,localStream 发生变化。在所有这些情况下,它都会将 'answering' 记录到控制台。

我可以添加 '// eslint-disable-next-line react-hooks/exhaustive-deps' 并且只添加 callState 但有很多文章对此提出警告:

https://dev.to/aman_singh/why-effects-shouldn-t-lie-about-their-dependencies-1645

https://betterprogramming.pub/stop-lying-to-react-about-missing-dependencies-10612e9aeeda

我在这里错过了什么?

只需要将callState添加到数组依赖中,将其余逻辑移至单独的方法中,仅当callState的值发生变化时才调用useEffect中的方法。

  const [localStream, setLocalStream] = useState();
  const [remoteStream, setRemoteStream] = useState();
  const [remoteRequest, setRemoteRequest] = useState();
  const [currentUser, setCurrentUser] = useState();
  const [callState, setCallState] = useState();

  const answerCall = useCallback(async() => {
     console.log('remoteStream', remoteStream);
     console.log('localStream', localStream);
     console.log('currentUser', currentUser);
     console.log('remoteStream', remoteRequest);
  }, [localStream, remoteStream, remoteRequest, currentUser]);

  useEffect(() => {
     (async () => {
      if (callState) {
        answerCall()
      }
     )()
  }, [callState]);