Skip to content

react-db's useLiveQuery seems to leave an extra subscriber in StrictMode #1178

@tec27

Description

@tec27
  • I've validated the bug against the latest version of DB packages

Describe the bug
In a pretty simple setup with a conditional query, I'm seeing 2 subscribers get created and only 1 get cleaned up when the component unmounts, which leaves the collection syncing permanently.

To Reproduce
Steps to reproduce the behavior:

  1. Set up a collection:
export const buildLogsCollection = createCollection<BuildLog>(
  electricCollectionOptions({
    id: "build-logs",
    shapeOptions: {
      url: `${BASE_URL}/shapes/build-logs`,
    },
    syncMode: "on-demand",
    getKey: (item) => item.id,
    gcTime: 1,
  }),
);

// Debug: track collection lifecycle
buildLogsCollection.on("status:change", (event) => {
  console.log("[build-logs] status:", event.status, "prev:", event.previousStatus);
});
buildLogsCollection.on("subscribers:change", (event) => {
  console.log(
    "[build-logs] subscribers:",
    event.subscriberCount,
    "prev:",
    event.previousSubscriberCount,
  );
});
  1. Create a hook to use the collection data:
export const useBuildLogs = (ownerId?: string) => {
  const { data } = useLiveQuery(
    (query) => {
      if (!ownerId) return undefined;

      return query
        .from({ log: buildLogsCollection })
        .where(({ log }) => eq(log.ownerId, ownerId))
        .orderBy(({ log }) => log.createdAt);
    },
    [ownerId],
  );
  return data;
};
  1. Use the hook in a component:
function App() {
  return <StrictMode><AppContent /></StrictMode>
}

function AppContent() {
  const [showLogs, setShowLogs] = useState(false);
  return <div>
    <button onClick={() => setShowLogs(v => !v)}>Toggle Logs</button>
    {showLogs && <BuildLogs />}
  </div>
}

function BuildLogs() {
    const logs = useBuildLogs("foo");
    return <div>{JSON.stringify(logs)}</div>
}
  1. Run the app in development mode (so StrictMode is used)

Expected behavior
After toggling logs on and then back off, the build-logs URL should stop being retrieved once gcTime expires, and should log as having 0 subscribers.

Desktop (please complete the following information):

  • Browser: Chrome
  • Version: 144

Additional context
With StrictMode off I see the correct behavior (1 subscriber added, 1 subscriber removed)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions