为啥在 useEffect 中侦听套接字事件时对服务器有多个请求?
Posted
技术标签:
【中文标题】为啥在 useEffect 中侦听套接字事件时对服务器有多个请求?【英文标题】:Why I having multiple requests to the server when listening to socket event inside useEffect?为什么在 useEffect 中侦听套接字事件时对服务器有多个请求? 【发布时间】:2021-07-16 00:34:13 【问题描述】:我收到了多个请求,尽管节点 js 服务器内只发出了一个事件。我只想在服务器发出事件时重新渲染我的组件,以便通知用户已成功完成。 这是我从服务器获取数据的自定义钩子:
import useCallback, useState from 'react';
export const useFetch = () =>
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const request = useCallback(async (url, method='GET', body = null, headers = ) =>
setLoading(true)
try
if(body)
body = JSON.stringify(body)
headers['Content-Type'] = 'application/json'
const response = await fetch(url, method, body, headers)
const data = await response.json()
if(!response.ok)
throw new Error(data.msg || 'Что-то пошло не так!')
setLoading(false)
return data
catch (e)
setLoading(false)
setError(e.message)
throw e
, [])
const clearError = () => setError(null)
return [loading, error, request, clearError]
这是我的 home.js 文件代码,我正在从服务器获取数据:
const Home = () =>
const [loading, error, request, clearError] = useFetch()
const [tables, setTables] = useState(null)
useEffect(() =>
const handleFetchTables = async() =>
try
const data = await request('/api/table/getAllTablesForCash')
setTables(data)
catch (_)
console.log(_.message)
clearError()
handleFetchTables()
socketIO.on('new_order_finished', async() => handleFetchTables())
socketIO.on('order_closed', async() => handleFetchTables())
, [request])
const handleTables = () =>
if(loading) return <CustomSpinner />
if(error) return <NetworkError />
return tables && (
tables.length ? (
<div style=styles.main>
tables.reverse().map((t, i) =>
return (
<TableCard key=i t=t />
)
)
</div>
) : (
<EmptyBag />
)
)
return (
<div style=styles.container>
<HomeHeader />
handleTables()
</div>
)
.png
【问题讨论】:
请帮忙!它对性能有很大影响。特别是当我有更多的订单时,它会获取大约 21-22 次span>handleFetchTables
是否有可能以某种方式触发new_order_finished
或order_closed
?另外,为什么request
在useEffect
依赖项中,而它的身份没有改变(由于useCallback
)?
放几个console.log
,应该会更清楚。 handleFetchTables
在两种情况下运行:1)作为效果运行 2)在套接字事件上运行。该效果在安装时运行,然后一旦request
的身份发生更改。 request
的身份没有改变(它是由useCallback
返回的,我没有看到它的使用有任何错误),所以我们剩下两种情况:1)组件Home
实际上正在重新安装(已安装 + 未安装)多次,无论出于何种原因,都会触发效果。 2) 套接字事件运行多次。
我建议您将其简化为一个最小的、可重现的示例。这将有助于发现问题。
另外,一旦Home
卸载,您就不会取消订阅套接字事件。因此,一旦您导航出Home
,然后再次导航回Home
,您将拥有越来越多的冗余侦听器,每次导航返回Home
时都会发送越来越多的请求。 Webpack 的开发服务器会在每次更改代码时重新加载,并且它也不会取消订阅事件。
【参考方案1】:
在您的 home.js 中,每次请求发生变化时都会调用 useEffect。 useEffect 块包含订阅套接字发出的事件的代码。因此,每次调用 useEffect 以更改“请求”时,您都在为该事件创建另一个订阅者。所以如果一个事件被触发,它会多次调用订阅的函数。
尝试从当前的 useEffect 中删除 [request] 部分。如果您真的想根据“请求”对象的更改做某事,请使用另一个 useEffect 块并且不要将事件订阅者放入其中。或者尝试在当前 useEffect 块的开头取消订阅,但这不是一个好的解决方案。希望这能解决您的问题
【讨论】:
为什么request
的身份会改变?据我所知,这是useCallback
以[]
作为部门的功能备忘录。以上是关于为啥在 useEffect 中侦听套接字事件时对服务器有多个请求?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 UseEffect 中将事件侦听器添加到 UseRefs
如何正确地将事件侦听器添加到 React useEffect 挂钩?
useEffect 中的套接字连接事件在创建组件时不起作用,但在 React 中刷新页面后起作用