Sardorek Aminjonov
Sardorek Aminjonov

Reputation: 834

Why I having multiple requests to the server when listening to socket event inside useEffect?

I am getting multiple requests although only one event is emitted inside node js server. I want to rerender my component only once when event is emitted from the server in order to notify the user that the has been completed successfully. This is my custom hook for fetching data from the server:

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]
}

This is my home.js file code, where I am fetching data from the server:

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

Upvotes: 0

Views: 618

Answers (1)

Imran Hossain
Imran Hossain

Reputation: 91

In your home.js, the useEffect is called each time there's a change in the request. The useEffect block contains code that subscribes to the event emitted by the socket. So each time useEffect is being called for a change in 'request', you are creating another subscriber to the event. So if an event is fired, it'll call the subscribed function multiple times.

Try removing the [request] part from the current useEffect. If you really want to do something based on the change in the 'request' object, use another useEffect block and don't put the event subscriber in that. Or try unsubscribing in the starting of your current useEffect block, but it's not a good solution. Hope this'll solve your issue

Upvotes: 1

Related Questions