diff --git a/packages/solid-react/src/useResource.ts b/packages/solid-react/src/useResource.ts index fb0d18a..fb3fffb 100644 --- a/packages/solid-react/src/useResource.ts +++ b/packages/solid-react/src/useResource.ts @@ -40,6 +40,7 @@ export function useResource( options?: UseResourceOptions, ): Leaf | Container | undefined { const { getResource } = useLdo(); + const subscriptionIdRef = useRef(); // Get the resource const resource = useMemo(() => { @@ -65,12 +66,15 @@ export function useResource( useEffect(() => { if (options?.subscribe) { - resource?.subscribeToNotifications(); - } else { - resource?.unsubscribeFromNotifications(); + resource + ?.subscribeToNotifications() + .then((subscriptionId) => (subscriptionIdRef.current = subscriptionId)); + } else if (subscriptionIdRef.current) { + resource?.unsubscribeFromNotifications(subscriptionIdRef.current); } return () => { - resource?.unsubscribeFromNotifications(); + if (subscriptionIdRef.current) + resource?.unsubscribeFromNotifications(subscriptionIdRef.current); }; }, [resource, options?.subscribe]); diff --git a/packages/solid-react/test/Integration.test.tsx b/packages/solid-react/test/Integration.test.tsx index d4d47dd..4497be4 100644 --- a/packages/solid-react/test/Integration.test.tsx +++ b/packages/solid-react/test/Integration.test.tsx @@ -372,7 +372,10 @@ describe("Integration Tests", () => { it("rerenders when asked to subscribe to a resource", async () => { const NotificationTest: FunctionComponent = () => { - const resource = useResource(SAMPLE_DATA_URI, { subscribe: true }); + const [isSubscribed, setIsSubscribed] = useState(true); + const resource = useResource(SAMPLE_DATA_URI, { + subscribe: isSubscribed, + }); const post = useSubject(PostShShapeType, `${SAMPLE_DATA_URI}#Post1`); const addPublisher = useCallback(async () => { @@ -389,12 +392,16 @@ describe("Integration Tests", () => { return (
+

+ {resource.isSubscribedToNotifications().toString()} +

+
); }; @@ -404,15 +411,17 @@ describe("Integration Tests", () => { , ); - const list = await screen.findByRole("list"); - expect(list.children[0].innerHTML).toBe("https://example.com/Publisher1"); - expect(list.children[1].innerHTML).toBe("https://example.com/Publisher2"); - // Wait for subscription to connect await act(async () => { await new Promise((resolve) => setTimeout(resolve, 1000)); }); + const list = await screen.findByRole("list"); + expect(list.children[0].innerHTML).toBe("https://example.com/Publisher1"); + expect(list.children[1].innerHTML).toBe("https://example.com/Publisher2"); + const resourceP = await screen.findByRole("resource"); + expect(resourceP.innerHTML).toBe("true"); + // Click button to add a publisher await fireEvent.click(screen.getByText("Add Publisher")); await screen.findByText("https://example.com/Publisher3"); @@ -423,11 +432,11 @@ describe("Integration Tests", () => { "https://example.com/Publisher3", ); - unmount(); + await fireEvent.click(screen.getByText("Unsubscribe")); + const resourcePUpdated = await screen.findByRole("resource"); + expect(resourcePUpdated.innerHTML).toBe("false"); - await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 1000)); - }); + unmount(); }); }); diff --git a/packages/solid/src/resource/notifications/NotificationSubscription.ts b/packages/solid/src/resource/notifications/NotificationSubscription.ts index 9e7d020..ce77b89 100644 --- a/packages/solid/src/resource/notifications/NotificationSubscription.ts +++ b/packages/solid/src/resource/notifications/NotificationSubscription.ts @@ -19,7 +19,7 @@ export abstract class NotificationSubscription { protected parentSubscription: (message: NotificationMessage) => void; protected context: SolidLdoDatasetContext; protected subscriptions: Record = {}; - protected isOpen: boolean = false; + private isOpen: boolean = false; constructor( resource: Resource, @@ -52,7 +52,7 @@ export abstract class NotificationSubscription { this.subscriptions[subscriptionId] = subscriptionCallbacks ?? {}; if (!this.isOpen) { await this.open(); - this.isOpen = true; + this.setIsOpen(true); } return subscriptionId; } @@ -67,7 +67,7 @@ export abstract class NotificationSubscription { Object.keys(this.subscriptions).length === 1 ) { await this.close(); - this.isOpen = false; + this.setIsOpen(false); } delete this.subscriptions[subscriptionId]; } @@ -128,7 +128,17 @@ export abstract class NotificationSubscription { onNotificationError?.(message); }); if (message.type === "disconnectedNotAttemptingReconnectError") { - this.isOpen = false; + this.setIsOpen(false); } } + + /** + * @internal + * setIsOpen + */ + protected setIsOpen(status: boolean) { + const shouldUpdate = status === this.isOpen; + this.isOpen = status; + if (shouldUpdate) this.resource.emit("update"); + } }