Reactjs 为什么我在useEffect中侦听套接字事件时对服务器有多个请求?

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

我收到多个请求,尽管在NodeJS服务器中只发出一个事件。我只想在服务器发出事件时重新启动组件一次,以便通知用户组件已成功完成。 这是我从服务器获取数据的自定义挂钩:

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。