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:
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
:
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
:
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.