ngneat/elf

Make `emitOnce` be stackable to use 2 child `emitOnce` inside parent `emitOnce`

EricPoul opened this issue · 3 comments

Which @ngneat/elf-* package(s) are relevant/releated to the feature request?

store

Description

If a store is quite complex you can have 2 methods of store updating with emitOnce inside and in the some moment you want to call these methods together but still have one emission of the store.

function updateOne() {
  emitOnce(() => {
    authStore.update((state) => ({
      ...state,
      user: { id: 'foo' },
    }));
    authStore.update((state) => ({
      ...state,
      user: { id: 'foo2' },
    }));
  });
}

function updateTwo() {
  emitOnce(() => {
    authStore.update((state) => ({
      ...state,
      user: { id: 'bar' },
    }));
    authStore.update((state) => ({
      ...state,
      user: { id: 'bar2' },
    }));
  });
}

function updateThree() {
  emitOnce(() => {
    updateOne();
    updateTwo();
  });
}

updateThree();

With the current implementation, we'll see two emissions
image

Proposed solution

export const batchInProgress = new BehaviorSubject<boolean>(false);
export const batchDone$ = batchInProgress.asObservable().pipe(
  filter((inProgress) => !inProgress),
  take(1)
);

export function emitOnce<T>(cb: () => T) {
  if (!batchInProgress.getValue()) {
    batchInProgress.next(true);
    const value = cb();
    batchInProgress.next(false);

    return value;
  }

  return cb();
}

Alternatives considered

Do you want to create a pull request?

Yes

Why not remove the emitOnce from the methods and use it only in updateThree?

first two methods could be called individually

Let's see a PR :)