Skip to main content

Cache

Using this feature, you can manage the cache status of API calls in your store. First, you need to install the package by using the CLI command elf-cli install and selecting the requests package, or via npm:

npm i @ngneat/elf-requests

To use this feature, provide the withRequestsCache props factory function in the createStore call:

todos.repository.ts
import { createStore } from '@ngneat/elf';
import { withEntities } from '@ngneat/elf-entities';
import { withRequestsCache } from '@ngneat/elf-requests';

interface Todo {
id: number;
label: string;
}

const todosStore = createStore(
{ name: 'todos' },
withEntities<Todo>(),
// You can pass the keys type
withRequestsCache<'todo'|`todo-${string}`>()
);

Now we can use the createRequestsCacheOperator function that takes a store and returns a custom operator.

import {
withRequestsCache,
createRequestsCacheOperator,
} from '@ngneat/elf-requests';

const todosStore = createStore(
{ name: 'todos' },
withEntities<Todo>(),
withRequestsCache<'todo'|`todo-${string}`>()
);

export const skipWhileTodosCached = createRequestsCacheOperator(todosStore);

We can use the resulting operator and pass a unique key to identify the request. This enables skipping the API call if the passed key is located in the store cache.

todos.service.ts
import { setTodos, skipWhileTodosCached } from './todos.repository';

export function fetchTodos() {
return http.get(todosUrl).pipe(
tap(setTodos(todos)),
skipWhileTodosCached('todos')
);
}

Use it in tandem with updateRequestsCache:

todos.repository.ts
import { updateRequestCache } from '@ngneat/elf-requests';
import { setEntities } from '@ngneat/elf-entities';

export function setTodos(todos: Todo[]) {
store.update(
updateRequestCache('todos'),
setEntities(todos)
);
}

Passing a value as the third parameter ensures the store will only skip the API call if the value matches the one passed. Values can be 'none', 'partial' or 'full':

todos.repository.ts
import { updateRequestCache } from '@ngneat/elf-requests';

export function setTodos(todos: Todo[]) {
store.update(
updateRequestCache('todos', { value: 'partial' }),
setEntities(todos)
);
}
todos.service.ts
import { setTodos, skipWhileTodosCached } from './todos.repository';

export function fetchTodos() {
return http.get(todosUrl).pipe(
tap((todos) => setTodos(todos)),
skipWhileTodosCached('todos', { value: 'partial' })
);
}

In addition to value, you can pass in the same object a returnSource which will be returned by the operator if the request is cached. The default return value is EMPTY observable.

todos.service.ts
import { skipWhileTodosCached, setTodos } from './todos.repository';

export function fetchTodos() {
return http.get(todosUrl).pipe(
tap((todos) => setTodos(todos)),
skipWhileTodosCached('todos', { returnSource: of([]) })
);
}

You can monitor and change the request cache status for your APIs using the following queries and mutations:

Queries

selectRequestCache

Select the cache status of the provided request key:

import { selectRequestCache } from '@ngneat/elf-requests';

todosCacheStatus$ = store.pipe(selectRequestCache('todos'));

getRequestCache

Get the cache status of the provided request key:

import { getRequestCache } from '@ngneat/elf-requests';

todosCacheStatus = store.query(getRequestCache('todos'));

selectIsRequestCached

Select whether the cache status of the provided request key isn't none:

import { selectIsRequestCached } from '@ngneat/elf-requests';

const isCached$ = store.pipe(selectIsRequestCached('todos'));
const isPartialCached$ = store.pipe(
selectIsRequestCached('todos', { value: 'partial' })
);

Get whether the cache status of the provided request key isn't none:

import { isRequestCached } from '@ngneat/elf-requests';

const isCached = store.query(isRequestCached('todos'));
const isPartialCached = store.query(
isRequestCached('todos', { value: 'partial' })
);

Mutations

updateRequestCache

import { updateRequestCache } from '@ngneat/elf-requests';

store.update(updateRequestCache('todos'));
store.update(updateRequestCache('todos', { value: 'partial' }));
store.update(updateRequestCache('todos', { value: 'none' }));
store.update(updateRequestCache('todos', { ttl: 1000 }));

If you pass ttl (time to live) when updating a cache record, that represents the time (in milliseconds) that key will have the value that was set (afterward, it reverts to 'none').

updateRequestsCache

import { updateRequestsCache } from '@ngneat/elf-requests';

store.update(
updateRequestsCache({
keyOne: {
value: 'partial',
},
})
);

store.update(updateRequestsCache(['keyOne', 'keyTwo'], { value: 'partial' }));

store.update(
updateRequestsCache(['keyOne', 'keyTwo'], { value: 'partial', ttl: 1000 })
);

If you pass ttl (time to live) when updating a cache record, that represents the time (in milliseconds) that key will have the value that was set (afterward, it reverts to 'none'). This parameter can be used to set individual ttl values for each key when updating multiple keys at once. If a ttl is not passed for a key, the value for that key does not expire.

clearRequestsCache

import { clearRequestsCache } from '@ngneat/elf-requests';

store.update(clearRequestsCache());

deleteRequestsCache

import { deleteRequestsCache } from '@ngneat/elf-requests';

store.update(deleteRequestsCache('keyOne'));

store.update(deleteRequestsCache(['keyOne', 'keyTwo']));