Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Realm.Results.removeAllListeners() not working #6028

Closed
rossicler-hostalky opened this issue Aug 1, 2023 · 6 comments
Closed

Realm.Results.removeAllListeners() not working #6028

rossicler-hostalky opened this issue Aug 1, 2023 · 6 comments

Comments

@rossicler-hostalky
Copy link

rossicler-hostalky commented Aug 1, 2023

How frequently does the bug occur?

Always

Description

Expected result:

Remove all listeners from a collection when calling results.removeAllListeners() method.

What actually happens:

When calling results.removeAllListeners() previously registered listeners are not removed.

Stacktrace & log output

No response

Can you reproduce the bug?

Always

Reproduction Steps

Example code:

export const getItems = async (shouldAddListeners: boolean) => {
  ...
  const items = realm.objects(ItemSchema);
  await realm.subscriptions.update((mutableSubs) => {
    mutableSubs.add(items, { name: "items" });
  })
  
  if (shouldAddListeners) {
    items.removeAllListeners(); // supposed to clean all listeners registered on previous
    items.addListener(itemListener);
  }
  ...
}

After calling this function for the second time, it duplicates the same listener.

Version

11.7.0

What services are you using?

Atlas Device Sync

Are you using encryption?

No

Platform OS and version(s)

macOS Monterey 12.6

Build environment

Electron ^23.0.0

Cocoapods version

No response

@takameyer
Copy link
Contributor

@rossicler-hostalky Thanks for posting this issue. We will investigate and get back to you.

@mednche
Copy link

mednche commented Aug 7, 2023

I have the same issue (realm-js 11.9.0).

function myFunction() {
    const records = siteRealm.objects("record")

    // FIRST REMOVE LISTENER!
    records.removeAllListeners()

    // Add new listener
    records.addListener(async (collection, changes) => {
        // My code
    }
}

Every time I call myFunction(), it creates a new instance of the listener but does not remove any existing ones.

This creates many issues in my app. Any idea what is causing it?

@takameyer
Copy link
Contributor

@rossicler-hostalky @mednche Hi there, the reason this is happening is that the listeners are applied to the instance of the returned collection. This is by design. Each time you call realm.objects, you get a new instance of the collection with no listeners applied.

The collections returned from realm.objects are "live". They will always contain the current state of the data, not a copy, so I recommend keeping the instances alive if you want to manage listener events.

// Keep the records in the scope of the module
const records = siteRealm.objects("record")

function myFunction() {
    // FIRST REMOVE LISTENER!
    records.removeAllListeners()

    // Add new listener
    records.addListener(async (collection, changes) => {
        // My code
    }
}

@rossicler-hostalky
Copy link
Author

rossicler-hostalky commented Aug 8, 2023

Hi @takameyer, is there any other way to remove listeners previously created? Maybe it should have the option to return a unsub function when adding a new listener, kind of similar to web js listeners.

My problem with this is that in the app I'm working we don't keep the "live" objects from realm, all results is always parsed to JSON objects, so changing that to keep the same instance of live objects between method calls will probably require some time to test and a lot of refactoring to work properly.

Example of how it could work:

const unsubListener;
export const getItems = async (shouldAddListeners: boolean) => {
  ...
  const items = realm.objects(ItemSchema);
  await realm.subscriptions.update((mutableSubs) => {
    mutableSubs.add(items, { name: "items" });
  })
  
  if (shouldAddListeners) {
    if (unsubListener) unsubListener();
    unsubListener = items.addListener(itemListener);
  }
  ...
}

This way we don't really need to keep "live" objects instance, but keep the unsubscribe function instead.

@rossicler-hostalky
Copy link
Author

I was able to manage this by keeping the reference of the function removeAllListeners, instead of all objects.

my code:

const unsubListener: () => void;
export const getItems = async (shouldAddListeners: boolean) => {
  ...
  const items = realm.objects(ItemSchema);
  await realm.subscriptions.update((mutableSubs) => {
    mutableSubs.add(items, { name: "items" });
  })
  
  if (shouldAddListeners) {
    if (unsubListener) unsubListener();
    items.addListener(itemListener);
    unsubListener = items.removeAllListeners;
  }
  ...
}

Although this should work with no problems, I would recommend to consider my suggestion on the comment above. And thanks for the reply clarifying this issue.

@takameyer
Copy link
Contributor

@rossicler-hostalky Happy you were able to find a workaround. Feel free to open a feature request. Aligning our event listeners on web js listeners sounds like an interesting enhancement.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants