在哪里使用React中的Hooks定义需要从全局状态获取数据的套接字事件监听器

时间:2020-04-27 06:30:28

标签: react-redux react-hooks use-effect use-context use-ref

我一直在学习钩子,一个概念仍然让我感到震惊。

使用useEffect时,在下一次重新渲染之后,内部声明的任何变量都会变旧。要访问useEffect内部的更改值,最常见的答案和一个Dan Abramov uses himself是使用useRef钩子。

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

我该如何组织一个可全局访问的状态,但也可以像可以访问useRef所做的引用一样引用该状态?

这是我的意思的示例

//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作为props。

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

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

先谢谢了。

1 个答案:

答案 0 :(得分: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])

}