progressive web apps - The real-time connection is not being restored - ReactJSPocketbase - Stack Overflow

I’m using PocketBase as the backend, with the frontend subscribing to it. The backend sends real-time u

I’m using PocketBase as the backend, with the frontend subscribing to it. The backend sends real-time updates to the frontend using Server-Sent Events (SSE). Everything works fine in the browser. When the app is installed as a PWA on a phone, the SSE connection is lost upon reopening the app after it has been minimized. Additionally, the page/data do not reload. The initial useEffect block containing router.refresh() does not trigger.

useVisibility.tsx

"use client";

import { useState, useEffect } from "react";

export function useVisibility() {
  const [isVisible, setVisible] = useState(true);

  useEffect(() => {
    const handleVisibilityChange = () => {
      setVisible(!document.hidden);
    };

    document.addEventListener("visibilitychange", handleVisibilityChange);
    return () => {
      document.removeEventListener("visibilitychange", handleVisibilityChange);
    };
  }, []);

  return isVisible;
}

AgendaLive.tsx

"use client";

import { Reservation } from "@/types";
import { useEffect } from "react";
import PocketBase from "pocketbase";
import { reservations } from "../tables";
import { useRouter } from "next/navigation";
import { useVisibility } from "@/hooks/useVisibility";

type Props = {
  token: string;
  date: string;
};

const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL);

export function AgendaLive({ token, date }: Props) {
  const router = useRouter();
  const isVisible = useVisibility();

  useEffect(() => {
    if (!isVisible) return;
    router.refresh();
  }, [isVisible, router]);

  useEffect(() => {
    if (!isVisible) return;

    pb.authStore.save(token);
    pb.collection(reservations).subscribe<Reservation>("*", (event) => {
      if (event.record.date !== date) {
        return;
      }
      router.refresh();
    });

    return () => {
      pb.collection(reservations).unsubscribe("*");
    };
  }, [token, date, router, isVisible]);

  return null;
}

I’m using PocketBase as the backend, with the frontend subscribing to it. The backend sends real-time updates to the frontend using Server-Sent Events (SSE). Everything works fine in the browser. When the app is installed as a PWA on a phone, the SSE connection is lost upon reopening the app after it has been minimized. Additionally, the page/data do not reload. The initial useEffect block containing router.refresh() does not trigger.

useVisibility.tsx

"use client";

import { useState, useEffect } from "react";

export function useVisibility() {
  const [isVisible, setVisible] = useState(true);

  useEffect(() => {
    const handleVisibilityChange = () => {
      setVisible(!document.hidden);
    };

    document.addEventListener("visibilitychange", handleVisibilityChange);
    return () => {
      document.removeEventListener("visibilitychange", handleVisibilityChange);
    };
  }, []);

  return isVisible;
}

AgendaLive.tsx

"use client";

import { Reservation } from "@/types";
import { useEffect } from "react";
import PocketBase from "pocketbase";
import { reservations } from "../tables";
import { useRouter } from "next/navigation";
import { useVisibility } from "@/hooks/useVisibility";

type Props = {
  token: string;
  date: string;
};

const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL);

export function AgendaLive({ token, date }: Props) {
  const router = useRouter();
  const isVisible = useVisibility();

  useEffect(() => {
    if (!isVisible) return;
    router.refresh();
  }, [isVisible, router]);

  useEffect(() => {
    if (!isVisible) return;

    pb.authStore.save(token);
    pb.collection(reservations).subscribe<Reservation>("*", (event) => {
      if (event.record.date !== date) {
        return;
      }
      router.refresh();
    });

    return () => {
      pb.collection(reservations).unsubscribe("*");
    };
  }, [token, date, router, isVisible]);

  return null;
}

Share Improve this question asked Mar 7 at 22:54 Tobias BenknerTobias Benkner 2001 gold badge2 silver badges10 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

Sometimes, visibilitychange events are not triggered reliably. Therefore, I introduced an isConnected variable to track the connection status.

  • isConnected = false when the app is left or the connection goes offline.
  • isConnected = true once the connection is successfully established.

When connecting, all current data is first fully loaded. After that, the system listens for changes in real time.

Components that need real-time data can use the corresponding hook and get all the important information in one place.

usePocketbaseRealtime.tsx

import { useEffect, useState } from "react";
import PocketBase from "pocketbase";

type Props = {
  collectionName: string;
  filter: string;
  token: string;
  sort: string;
  expand: string;
};

const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL);
export function usePocketbaseRealtime<T extends { id: string }>({
  collectionName,
  filter,
  token,
  sort,
  expand,
}: Props) {
  const [data, setData] = useState<T[]>([]);
  const [isConnected, setIsConnected] = useState(false);
  const [isOnline, setIsOnline] = useState<boolean>(true);

  async function setupRealtimeConnection() {
    if (!isOnline) {
      return;
    }

    pb.authStore.save(token);
    try {
      await pb.realtime.unsubscribe(collectionName);
      const records = await pb.collection(collectionName).getFullList<T>({
        filter: filter,
        sort: sort,
        expand: expand,
      });
      setData(records);

      await pb.realtime.subscribe(
        collectionName,
        (e) => {
          if (e.action === "create") {
            setData((prevData) => [...prevData, e.record]);
          } else if (e.action === "update") {
            setData((prevData) =>
              prevData.map((record) =>
                record.id === e.record.id ? e.record : record
              )
            );
          } else if (e.action === "delete") {
            setData((prevData) =>
              prevData.filter((record) => record.id !== e.record.id)
            );
          }
        },
        {
          filter: filter,
          expand: expand,
        }
      );

      setIsConnected(true);
    } catch (error) {
      console.error("Error Realtime-Connection:", error);
      setIsConnected(false);
    }
  }

  async function disconnectRealtime() {
    setIsConnected(false);
    await pb.realtime.unsubscribe(collectionName);
  }

  useEffect(() => {
    const handleOnline = () => {
      setIsOnline(true);
      setupRealtimeConnection();
    };

    const handleOffline = () => {
      setIsOnline(false);
      disconnectRealtime();
    };

    const handleVisibilityChange = () => {
      if (document.visibilityState === "visible") {
        setupRealtimeConnection();
      } else {
        disconnectRealtime();
      }
    };

    if (isOnline) {
      setupRealtimeConnection();
    }

    window.addEventListener("online", handleOnline);
    window.addEventListener("offline", handleOffline);
    document.addEventListener("visibilitychange", handleVisibilityChange);

    return () => {
      window.removeEventListener("online", handleOnline);
      window.removeEventListener("offline", handleOffline);
      document.removeEventListener("visibilitychange", handleVisibilityChange);
      disconnectRealtime();
    };
  }, [collectionName, filter]);

  return { data, isConnected, isOnline, reconnect: setupRealtimeConnection };
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744907488a4600343.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信