首页 > 解决方案 > 为什么在 useEffect 中侦听套接字事件时对服务器有多个请求?

问题描述

尽管在节点 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

标签: reactjssocket.ioreact-hooksfetchuse-effect

解决方案


在您的 home.js 中,每次请求发生变化时都会调用 useEffect。useEffect 块包含订阅套接字发出的事件的代码。因此,每次调用 useEffect 以更改“请求”时,您都在为该事件创建另一个订阅者。所以如果一个事件被触发,它会多次调用订阅的函数。

尝试从当前 useEffect 中删除 [request] 部分。如果您真的想根据“请求”对象中的更改做某事,请使用另一个 useEffect 块并且不要将事件订阅者放入其中。或者尝试在当前 useEffect 块的开头取消订阅,但这不是一个好的解决方案。希望这能解决您的问题


推荐阅读