Skip to main content

Batching

When using the store's update function, you can pass multiple mutation functions:

store.update(
setProp('count', 1),
addEntities([todo, todo]),
deleteEntities(1)
);

In this case, subscribers will only receive one emission instead of three.

emitOnce

There are cases where you have multiple update functions of the same store that you want to batch together. To do so you can use the emitOnce function:

todos.repository.ts
export function updateCount() {
store.update(
setProp('count', 1),
);
}

export function updateUser() {
store.update(
setProp('user', null),
);
}
import { emitOnce } from '@elf/store';
import { updateCount, updateUser } from './todos.repository';

emitOnce(() => {
updateCount();
updateUser();
});

In this case, subscribers will only receive one emission instead of two.

Also, you might face the need to use functions that use emitOnce inside another emitOnce:

table.repository.ts
export function restoreFilters() {
emitOnce(() => {
store.update(
setProp('filters', null),
);
resetPagination();
});
}

export function resetSort() {
emitOnce(() => {
store.update(
setProp('sort', null),
);
resetPagination();
});
}

export function resetPagination() {
store.update(
setProp('pagination', null),
);
}
import { emitOnce } from '@elf/store';
import { restoreFilters, resetSort } from './table.repository';

emitOnce(() => {
restoreFilters();
resetSort();
});

In this case, subscribers will only receive one emission instead of two.

emitOnceAsync

In some cases, you might need to use emitOnce with async functions or observables. To do so, you can use emitOnceAsync:

todos.repository.ts
export async function updateCount() {
const newCount = await fetchCount(); // Fetch count from API
store.update(setProp('count', newCount));
}

export async function updateUser() {
const newUser = await fetchUser(); // Fetch user from API
store.update(setProp('user', newUser));
}

export function clearCount() {
store.update(setProp('user', null));
}

export function clearUser() {
store.update(setProp('user', null));
}
import { emitOnceAsync } from '@elf/store';
import { updateCount, updateUser } from './todos.repository';

await emitOnceAsync(async () => {
await updateCount();
await updateUser();
});

In this case, subscribers will also only receive one emission instead of two.

You can also use emitOnce and emitOnceAsync inside another emitOnceAsync:

import { emitOnce, emitOnceAsync } from '@elf/store';
import { updateCount, updateUser } from './todos.repository';

async function updateCountAndUser() {
await emitOnceAsync(async () => {
await updateCount();
await updateUser();
});
}

await emitOnceAsync(async () => {
emitOnce(() => {
clearCount();
clearUser();
});
await updateCountAndUser();
});

You can also provide an observable to emitOnceAsync, in this case, the store will only update when the observable emits its first value.

Using emitOnceAsync inside emitOnce will not work as expected because emitOnce will not wait for the async function to finish.

Use emitOnceAsync with caution, the store will not update until the async function finishes or the observable emits its first value. If your async function or observable takes too long to finish, the app might appear unresponsive.