在 React 中使用 Hooks 在哪里定义需要来自全局状态的数据的套接字事件侦听器
Where to define socket event listeners that require data from global state using Hooks in React
我一直在学习钩子,但有一个概念仍然让我感到困惑。
使用 useEffect 时,在内部声明的任何变量在下一次重新渲染后都会变旧。要访问 useEffect 中不断变化的值,最常见的答案之一 Dan Abramov uses himself 是改用 useRef 挂钩。
但是,想象一下,您想要使用 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 之外还有更好的地方可以将事件侦听器添加到套接字?
提前致谢。
关于侦听器的想法是,它们应该在闭包值更新时销毁并重新创建,并在卸载时清理。您可以将用户依赖项添加到 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])
}
我一直在学习钩子,但有一个概念仍然让我感到困惑。
使用 useEffect 时,在内部声明的任何变量在下一次重新渲染后都会变旧。要访问 useEffect 中不断变化的值,最常见的答案之一 Dan Abramov uses himself 是改用 useRef 挂钩。
但是,想象一下,您想要使用 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 之外还有更好的地方可以将事件侦听器添加到套接字?
提前致谢。
关于侦听器的想法是,它们应该在闭包值更新时销毁并重新创建,并在卸载时清理。您可以将用户依赖项添加到 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])
}