0

I'm trying to debounce() an Observable with pipe() and chaining .subscribe() but for some reason the function in the subscribe is still being called over a dozen times in one go.

What I'm trying to do is pipe the withChangesForTables and debounce the sync call because I want it to be called only when a whole batch of changes have been made. So I created a provider for the sync and wrapped it around my RootNavigator

withChangesForTables on WatermelonDB source code

const SyncContext = createContext();
function useSync() {
    return useContext(SyncContext);
}

function SyncProvider({children}) {
    const [isSyncing, setIsSyncing] = useState(false);
    const [hasUnsynced, setHasUnsynced] = useState(false);

    async function checkUnsyncedChanges() {
        const hasChanges = await hasUnsyncedChanges({
            database
        });
        setHasUnsynced(hasChanges);
    }
    async function sync() {
        await checkUnsyncedChanges();
        if (!isSyncing && hasUnsynced) {
            setIsSyncing(true);
            await synchronizeWithServer();
            setIsSyncing(false);
        }
    }

    
    database.withChangesForTables([
        'table_name',
        'table_name2'
    ]).pipe(
        skip(1),
        // ignore records simply becoming `synced`
        filter(changes => !changes.every(change => change.record.syncStatus === 'synced')),
        // debounce to avoid syncing in the middle of related actions - I put 100000 to test only
        debounceTime(100000),
    ).subscribe({
        //calls API endpoint to sync local DB with server
        next: () => sync(), 
        error: e => console.log(e)
    });

    const value = {
        isSyncing,
        hasUnsynced,
        checkUnsyncedChanges,
        sync
    };

    return (
        <SyncContext.Provider value={value}>
            {children}
        </SyncContext.Provider>
    );
}
Ryker
  • 446
  • 3
  • 14
  • do you subscribe multiple times? – ggradnig Dec 16 '21 at 16:26
  • @ggradnig Sorry if this is a dumb question as I'm very new to rxjs but how do i know if I'm subscribing multiple times? I basically have this code in a provider that I created. The provider is then wrapped around the RootNavigator – Ryker Dec 16 '21 at 16:33
  • So the question would be how often you execute the code that you've posted. For example, add a `console.log` statement to your code and see how often it is logged. It should only be once! – ggradnig Dec 16 '21 at 16:40
  • @ggradnig So the code is executed every time there is a change to the local database so I actually need it to run multiple times but I just don't want it to run 100x/second. I only want it to run once every second at most – Ryker Dec 16 '21 at 16:47
  • I would assume your component is being rendered multiple times. Also how do you unsubscribe? Try adding something like `take(1)` after `skip(1)`; – GEMI Dec 23 '21 at 20:31
  • @GEMI Sorry I actually had figured out my problem a bit ago but forgot to post the solution! Just added an answer just now, thanks so much for taking the time to reply! – Ryker Jan 04 '22 at 21:35

1 Answers1

0

I had to move withChangesForTables into a useEffect and retrun it in order to unsubcribe which seems to have resolved the issue. The code now looks something like this:

useEffect(() => {
    return database.withChangesForTables([
        'table_name',
        'table_name2'
    ]).pipe(
        skip(1),
        filter(changes => !changes.every(change => change.record.syncStatus === 'synced')),
        debounceTime(500),
    ).subscribe({
        next: () => sync(), 
        error: e => console.log(e)
    });
}, [])
Ryker
  • 446
  • 3
  • 14