admin管理员组

文章数量:1417555

I have a react app that is a helpcenter with articles. I am working on a feature to send information to the backend about how long an user has viewed an article.

For normal app flow (e.g. navigating away from an article to another page), I am using React Query and sending the request in the cleanup function for an useEffect. This works fine.

I am also trying to send the request upon page refresh or when closing the page. I am using fetch with keepalive: true in an beforeunload and also pagehide events, so that the request is sent even though the page is closed. Here is an useEffect showing all this logic:

useEffect(() => {
    lastActiveRef.current = new Date();
    isTrackingRef.current = true;
    const hasSentRef = { current: false };

    const sendTime = (isUnload = false) => {
      if (hasSentRef.current) return;
      hasSentRef.current = true;

      let finalTime = activeSecondsRef.current;
      if (isTrackingRef.current) {
        const currentSession = Math.floor(
          (Date.now() - lastActiveRef.current.getTime()) / 1000
        );
        finalTime += currentSession;
      }

      if (finalTime > 1) {
        console.log("Tracking time:", articleId, finalTime);

        // console.log("sendBeacon", navigator.sendBeacon);

        if (isUnload) {
          // Use sendBeacon for unload events
          console.log("Sending beacon:", finalTime);
          
          fetch(
            `${
              import.meta.env.VITE_BACKEND_URL
            }/public/add-view-duration/${articleId}?viewDuration=${finalTime}`,
            {
              method: "POST",
              keepalive: true,
            }
          ).catch((error) => console.error("Request failed:", error));
        } else {
          // Use normal mutation for component unmount
          const id = parseInt(articleId ?? "");
          sendTimeSpent({ articleId: id, seconds: finalTime });
        }
      }
    };

    const handleUnload = () => {
      sendTime(true);
      console.log("page has refreshed or closed");
    };

    window.addEventListener("beforeunload", handleUnload);
    window.addEventListener("pagehide", handleUnload);

    return () => {
      sendTime(false); // Normal component unmount
      window.removeEventListener("beforeunload", handleUnload);
      window.removeEventListener("pagehide", handleUnload);
    };
  }, [articleId]);

The issue is that while handleUnload() is called correctly (tested with the console log) upon refresh, the request fails. Sometimes it works properly, but most of the time is showed as cancelled in the network tab.

I have also tried to use sendBeacon instead, but it doesn't send any request at all. I have tried with adblocker turned off and in other browsers or in incognito mode.

Everything related to the backend is fine, since the react query mutation works with no issue

What might the issue be?

本文标签: reactjsfetch with keepalive not firing in beforeunload eventStack Overflow