Search code examples
javascriptreactjsuse-effect

React useEffect cleanup for event listener


In my React component, I have a event handling for beforeunload. I want to clean that up in my useEffect return. Is the below code the correct way of doing the same or is there any better way ?

useEffect(() => {
    if (Object.keys(someKey).length > 0) {
        function callSvc(urls) {
        }
        callSvc(urls);
        
        const intV = setInterval(callSvc, interval, urls);
        window.addEventListener("beforeunload", function() {clearInterval(intV)});

        return () => {
            //window.removeEventListener("beforeunload", function() {clearInterval(intV)});
        }
    }
}, [someKey])

UPDATED CODE

useEffect(() => {
    if (Object.keys(someKey).length > 0) {
        const intV = setInterval(callSvc, interval, urls);
        function clearTimer() {
            clearInterval(intV)
        }
        window.addEventListener("beforeunload", clearTimer);
        return () => {
            window.removeEventListener("beforeunload", clearTimer);
        }
    }
}, [someKey])

Solution

  • Is the below code the correct way of doing the same or is there any better way ?

    There is a crucial problem with your code: Removing an event handler only works if you pass exactly the same function to removeEventListener that you passed to addEventListener. But as it stands you are passing two different functions. This is easy to solve buy storing the function in a variable and reference that variable in both addEventListener and removeEventListener.

    However, I question whether the beforeunload event handler is even necessary. When the page is closed any JS code stops running anyway. I think it's more important to stop the interval when the effect re-runs, otherwise you are starting a new interval whenever the effect runs again, resulting in multiple parallel intervals:

    useEffect(() => {
        if (Object.keys(someKey).length > 0) {
            function callSvc(urls) {
            }
            callSvc(urls);
            
            const intV = setInterval(callSvc, interval, urls);
            return () => {
                clearInterval(intV)
            }
        }
    }, [someKey])