schema.Collection
Collections
are entities but for Arrays or Values.
This makes them well suited at handling mutations. You can add to Array Collections
with .push or .unshift and
Values Collections
with .assign.
RestEndpoint provides .push, .unshift, .push and .paginate extenders
Usage
[{"id":"1","username":"bob","name":"Bob","todos":[{"id":"123","title":"Build Collections","userId":"1"},{"id":"456","title":"Add atomic creation","userId":"1"}]},{"id":"2","username":"alice","name":"Alice","todos":[{"id":"34","title":"Use Collections","userId":"2"},{"id":"453","title":"Make a fast web app","userId":"2"}]}]
response(body){return{id:(0,uuid__WEBPACK_IMPORTED_MODULE_8__/* ["default"] */ .Z)(),...body};}
import { getTodos } from './api/Todo';export default function NewTodo({ userId }: { userId?: string }) {const ctrl = useController();const [unshift, setUnshift] = React.useState(false);const handlePress = React.useCallback(async (e: React.KeyboardEvent) => {if (e.key === 'Enter') {const createTodo = unshift ? getTodos.unshift : getTodos.push;ctrl.fetch(createTodo, { title: e.currentTarget.value, userId });e.currentTarget.value = '';}},[ctrl, unshift],);return (<div><input type="text" onKeyDown={handlePress} /><label><inputtype="checkbox"checked={unshift}onChange={e => setUnshift(e.currentTarget.checked)}/>{' '}unshift</label></div>);}
Options
argsKey(...args): Object
Returns a serializable Object whose members uniquely define this collection based on Endpoint arguments.
import { schema, RestEndpoint } from '@rest-hooks/rest';
const getTodos = new RestEndpoint({
path: '/todos',
searchParams: {} as { userId?: string },
schema: new schema.Collection([Todo], {
argsKey: (urlParams: { userId?: string }) => ({
...urlParams,
}),
}),
});
nestKey(parent, key): Object
Returns a serializable Object whose members uniquely define this collection based on the parent it is nested inside.
import { schema, Entity } from '@rest-hooks/rest';
class Todo extends Entity {
id = '';
userId = '';
title = '';
completed = false;
pk() {
return this.id;
}
static key = 'Todo';
}
class User extends Entity {
id = '';
name = '';
username = '';
email = '';
todos: Todo[] = [];
pk() {
return this.id;
}
static key = 'User';
static schema = {
todos: new schema.Collection([Todo], {
nestKey: (parent, key) => ({
userId: parent.id,
}),
}),
};
}
createCollectionFilter?
Sets a default createCollectionFilter
for addWith(),
push, unshift, and assign.
This is used by these creation schemas to determine which collections to add to.
Default:
const defaultFilter =
(urlParams: Record<string, any>, body?: Record<string, any>) =>
(collectionKey: Record<string, string>) =>
Object.entries(collectionKey).every(
([key, value]) =>
key.startsWith('order') ||
// double equals lets us compare non-strings and strings
urlParams[key] == value ||
body?.[key] == value,
);
Methods
push
A creation schema that places at the end of this collection
unshift
A creation schema that places at the start of this collection
assign
A creation schema that assigns
its members to the Collection
.
addWith(merge, createCollectionFilter): CreationSchema
Constructs a custom creation schema for this collection. This is used by push, unshift, assign and paginate
merge(collection, creation)
This merges the value with the existing collection
createCollectionFilter
This function is used to determine which collections to add to. It uses the Object returned from argsKey or nestKey to determine if that collection should get the newly created values from this schema.
Because arguments may be serializable types like number
, we recommend using ==
comparisons,
e.g., '10' == 10
(...args) => collectionKey => boolean
Lifecycle Methods
static shouldReorder(existingMeta, incomingMeta, existing, incoming): boolean
static shouldReorder(
existingMeta: { date: number; fetchedAt: number },
incomingMeta: { date: number; fetchedAt: number },
existing: any,
incoming: any,
) {
return incomingMeta.fetchedAt < existingMeta.fetchedAt;
}
true
return value will reorder incoming vs in-store entity argument order in merge. With
the default merge, this will cause the fields of existing entities to override those of incoming,
rather than the other way around.
static merge(existing, incoming): mergedValue
static merge(existing: any, incoming: any) {
return incoming;
}
static mergeWithStore(existingMeta, incomingMeta, existing, incoming): mergedValue
static mergeWithStore(
existingMeta: { date: number; fetchedAt: number },
incomingMeta: { date: number; fetchedAt: number },
existing: any,
incoming: any,
): any;
mergeWithStore()
is called during normalization when a processed entity is already found in the store.
pk: (parent?, key?, args?): pk?
pk()
calls argsKey or nestKey depending on which are specified, and
then serializes the result for the pk string.
pk(value: any, parent: any, key: string, args: readonly any[]) {
const obj = this.argsKey
? this.argsKey(...args)
: this.nestKey(parent, key);
for (const key in obj) {
if (typeof obj[key] !== 'string') obj[key] = `${obj[key]}`;
}
return JSON.stringify(obj);
}