Reactjs 为什么我在useEffect中侦听套接字事件时对服务器有多个请求?
我收到多个请求,尽管在NodeJS服务器中只发出一个事件。我只想在服务器发出事件时重新启动组件一次,以便通知用户组件已成功完成。 这是我从服务器获取数据的自定义挂钩:Reactjs 为什么我在useEffect中侦听套接字事件时对服务器有多个请求?,reactjs,socket.io,react-hooks,fetch,use-effect,Reactjs,Socket.io,React Hooks,Fetch,Use Effect,我收到多个请求,尽管在NodeJS服务器中只发出一个事件。我只想在服务器发出事件时重新启动组件一次,以便通知用户组件已成功完成。 这是我从服务器获取数据的自定义挂钩: import { useCallback, useState } from 'react'; export const useFetch = () => { const [loading, setLoading] = useState(false) const [error, setError] = use
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]
}
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>
)
}
这是我的home.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]
}
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>
)
}
const Home=()=>{
const[loading,error,request,clearError]=useFetch()
常量[表,设置表]=useState(null)
useffect(()=>{
const handleFetchTables=async()=>{
试一试{
const data=wait请求('/api/table/getAllTablesForCash')
可设置(数据)
}接住{
console.log(u.message)
clearError()
}
}
handleFetchTables()
on('new\u order\u finished',async()=>handleFetchTables())
on('order_closed',async()=>handleFetchTables())
},[请求])
const handleTables=()=>{
如果(正在加载)返回
如果(错误)返回
返回表&&(
桌子。长度(
{
tables.reverse().map((t,i)=>{
返回(
)
})
}
) : (
)
)
}
返回(
{handleTables()}
)
}
.png在your home.js中,每次请求发生更改时都会调用useEffect。useEffect块包含订阅套接字发出的事件的代码。因此,每次调用useEffect更改“请求”时,您都在为事件创建另一个订阅服务器。因此,如果触发一个事件,它将多次调用订阅的函数
尝试从当前useEffect中删除[request]部分。如果您确实希望根据“request”对象中的更改来执行某些操作,请使用另一个useffect块,不要将事件订阅服务器放在该块中。或者尝试在当前useEffect块开始时取消订阅,但这不是一个好的解决方案。希望这能解决您的问题请帮助!这对性能影响很大。特别是当我有更多的订单时,它的回迁时间大约为21-22倍。
handleFetchTables
是否可能触发new\u order\u finished
或order\u closed
?另外,为什么request
在useffect
依赖项中,当其标识没有更改(由于useCallback
)时?放置一些console.log
,这样应该会更清楚。handleFetchTables
在两种情况下运行:1)效果在套接字事件上运行2)。该效果在装载时运行,然后一旦请求
的标识发生更改。request
的标识没有改变(它是由useCallback
返回的,并且我看不到它的使用中有任何错误),因此我们只剩下两种情况:1)组件Home
实际上由于任何原因被多次重新装载(装载+卸载),从而触发效果。2) 套接字事件运行多次。我建议您将其简化为一个最小的、可重复的示例。这将有助于发现问题。此外,一旦Home
unmounts,您就不会取消订阅套接字事件。因此,一旦您导航出主页
,然后再次返回主页
,您将拥有越来越多的冗余侦听器,每次导航回主页
,都会发送越来越多的请求。网页包的开发服务器在每次代码更改时都会重新加载,而且它也不会取消订阅事件。为什么会请求的身份更改?据我所知,这是一个由useCallback
编写的函数备忘录,其中[]
为deps。