2

我一直在学习钩子,但一个概念仍然让我感到困惑。

使用 useEffect 时,内部声明的任何变量在下一次重新渲染后都会变旧。要访问 useEffect 中不断变化的值,最常见的答案,也是Dan Abramov 自己使用的一个方法,是改用 u​​seRef 挂钩。

但是,假设您想使用 Redux 之类的东西将一条信息存储在全局状态中,但您还希望该信息在 useEffect 内部的回调函数中可用。在我的特定情况下,当我的组件挂载时,我需要将事件侦听器添加到连接到服务器的 Web 套接字,以发出 WebRTC 连接的信号。Web 套接字侦听器回调函数所需的值将在整个应用程序的使用过程中更新。

如何组织一个全局可访问的状态,但也可以像访问 useRef 生成的 ref 一样被引用?

这是我的意思的一个例子

//App.js 
import React, {useEffect} from "react"
import {useSelector} from "react-redux"

import socketIOClient from "socket.io-client";

const App = () => {

   const users = useSelector(state => state.users)

   let socket 

   //when the component mounts, we establish a websocket connection and define the listeners 
   useEffect(() => {
      socket = socketIOClient(URL)

   //in my app in particular, when the user decides to broadcast video, they must make new RTCPeerConnections
   //to every user that has logged in to the application as well 
      socket.on("requestApproved", () => {
         //at this point, the users array is outdated
         users.forEach(callbackToCreateRTCPeerConnection)
      })
   }, [])

} 

当客户端从服务器收到他们可以开始广播的响应时,客户端需要准确反映哪些用户在使用应用程序的整个过程中登录。显然,此时的值users是陈旧的,因为即使来自 useSelector 的值也不会在 useEffect 内部更新,尽管它在外部。所以我可以在这里使用 useRef 来实现我想要的,但这不是我使用 users 数组的唯一地方,我不想一遍又一遍地传递一个 ref 作为道具。

我已经阅读了有关使用 useContext 的信息,但是,如果我理解正确,当上下文值发生变化并且整个应用程序正在使用上下文时,就会为整个应用程序触发重新渲染。

有什么想法、建议、解释吗?除了 useEffect 之外,也许还有更好的地方可以将事件侦听器添加到套接字?

提前致谢。

4

1 回答 1

1

关于监听器的想法是它们应该在闭包值更新时被销毁并重新创建,并在卸载时清理。您可以将用户依赖项添加到useEffect并清理侦听器

const App = () => {

   const users = useSelector(state => state.users)

   let socket 

   //when the component mounts, we establish a websocket connection and define the listeners 
   useEffect(() => {
      socket = socketIOClient(URL)

   //in my app in particular, when the user decides to broadcast video, they must make new RTCPeerConnections
   //to every user that has logged in to the application as well 
      const listener = () => {
         //at this point, the users array is outdated
         users.forEach(callbackToCreateRTCPeerConnection)
      }
      socket.on("requestApproved", listener);

      return () => {
         socket.off("requestApproved", listener);
      }

   }, [users])

} 
于 2020-04-27T09:13:10.253 回答