Search code examples
postgresqlsupabasesupabase-databasesupabase-jssupabase-realtime

How to subscribe to a supabase realtime channel multiple times?


Situation

How can I design a feature that a user can visit a page, subscribe to real-time changes and unsubscribe if the user navigates away from the page using Supabase realtime (PostgreSQL)?

By using an Angular Frontend, my idea has been to use a service that implements the channel. If the user navigates to the component, the user subscribes to the channel. If the user navigates away and the component is destroyed, the user unsubscribes.

This works fine, but if I navigate again to the page, it throws the following error:

ERROR tried to subscribe multiple times. 'subscribe' can only be called a single time per channel instance

Question

What is the best solution for this case? Do I have to create a new channel instance each time a user visits a page? If yes, what is the best approach to do that?

My code

Channel in service:

private notificationsChannel: RealtimeChannel = supabaseClient
    .channel('notificationsChannel')
    .on('postgres_changes', {
...
})``

Method to subscribe in service:

public subscribeToRealtimeNotifications(): void {
    this.notificationsChannel.subscribe()
}

Method unsubscribe in service:

public async unsubscribeToRealtimeNotifications(): Promise<void> {
    const response = await this.notificationsChannel.unsubscribe()
}`

The component subscribes in the angular ngOnInit lifecycle hook:

async ngOnInit(): Promise<void> {
    this.notificationsService.subscribeToRealtimeNotifications()
}

The component unsubscribes in the angular ngOnDestroy lifecycle hook:

async ngOnDestroy(): Promise<void> {
    await this.notificationsService.unsubscribeToRealtimeNotifications()
}

The same happens if use this.supabaseClient.removeChannel(this.notificationsChannel)


Solution

  • Do I have to create a new channel instance each time a user visits a page? If yes, what is the best approach to do that?

    Yes, you do.

    Why not simply create a new channel instance right before you subscribe?

    public subscribeToRealtimeNotifications(): void {
        this.notificationsChannel = supabaseClient
          .channel('notificationsChannel')
          .on('postgres_changes', {
        ...
        })
        this.notificationsChannel.subscribe()
    }