useDatx API
useInitialize
On the server side it is important to create an entirely new instance of Datx Client for each request. Otherwise, your response to a request might include sensitive cached query results from a previous request.
const client = useInitialize(() => new Client());
useClient
For accessing Client
instance from the context. It's made mainly for internal usage.
const client = useClient();
useDatx
const expression: IGetManyExpression<typeof Todo> = {
op: 'getMany',
type: 'todos',
};
const config: DatxConfiguration<Todo, Array<Todo>> = {
// datx config
networkConfig: {
headers: {
'Accept-Language': 'en',
}
},
// SWR config
onSuccess: (data) => console.log(data.data[0].id),
}
const = useDatx(expression, config);
Second parameter of useDatx
is for passing config options. It extends default SWR config prop with additional networkConfig
property useful for passing custom headers.
Expression signature
Currently, we support 5 expressions for fetching resources getOne
, getMany
, getAll
, getRelatedResource
and getRelatedResources
.
// fetch single resource by id
export interface IGetOneExpression<TModel extends JsonapiModelType = JsonapiModelType> {
readonly op: 'getOne';
readonly type: TModel['type'];
id: string;
queryParams?: IRequestOptions['queryParams'];
}
// fetch resource collection
export interface IGetManyExpression<TModel extends JsonapiModelType = JsonapiModelType> {
readonly op: 'getMany';
readonly type: TModel['type'];
queryParams?: IRequestOptions['queryParams'];
}
// fetch all the pages of resource collection
export interface IGetAllExpression<TModel extends JsonapiModelType = JsonapiModelType> {
readonly op: 'getAll';
readonly type: TModel['type'];
queryParams?: IRequestOptions['queryParams'];
maxRequests?: number | undefined;
}
// fetch single related resource through the primary resource
export interface IGetRelatedResourceExpression<
TModelType extends JsonapiModelType = JsonapiModelType,
> {
readonly op: 'getRelatedResource';
readonly type: TModelType['type'];
readonly relation: string;
id: string;
queryParams?: IRequestOptions['queryParams'];
}
// fetch a collection of related resources through the primary resource
export interface IGetRelatedResourcesExpression<
TModelType extends JsonapiModelType = JsonapiModelType
> {
readonly op: 'getRelatedResources';
readonly type: TModelType['type'];
readonly relation: string;
id: string;
queryParams?: IRequestOptions['queryParams'];
}
useDatxInfinite
For fetching paginated data. It uses useSWRInfinite
internally so all the options from the documentation can be applied to useDatxInfinite
.
const getPageExpression = (index: number, size = 10) => ({
op: 'getMany',
type: 'todos',
queryParams: {
custom: [
{ key: 'page[index]', value: String(index) },
{ key: 'page[size]', value: String(size) },
] as const,
},
} as const satisfies IGetManyExpression<typeof Todo>);
// omit `satisfies IGetManyExpression<typeof Todo>` if you are using typescript < 4.9
const config: DatxInfiniteConfiguration<Todo> = {
// datx config
networkConfig: {
headers: {
'Accept-Language': 'en',
}
},
// SWR config
onSuccess: (data) => console.log(data[0].data[0].id),
}
const getKey = (pageIndex: number, previousPageData: CollectionResponse) => {
if (previousPageData && previousPageData.data.length === 0) return null;
return getPageExpression(pageIndex);
};
const { data: responses, error, size, setSize } = useDatxInfinite(getKey, config);
Second parameter of useDatxInfinite
is for passing config options. It extends default SWRInfinite config prop with additional networkConfig
property useful for passing custom headers.
Core expression should always be a
getMany
operation.
useMutation
A hook for remote mutations. This is a helper hook until this is merged to SWR core!
// ./src/queries/todo.ts
import { IGetManyExpression } from '@datx/swr';
import { Todo } from '../models/Todo';
export const querytodos: IGetManyExpression<typeof Todo> = {
op: 'getMany',
type: 'todos',
};
// ./src/mutations/todo.ts
import { getModelEndpointUrl, modelToJsonApi } from '@datx/jsonapi';
import { IClientInstance } from '@datx/swr';
import { Todo } from '../models/Todo';
export const createTodo = (client: IClientInstance, message: string | undefined) => {
const model = new Todo({ message });
const url = getModelEndpointUrl(model);
const data = modelToJsonApi(model);
return client.request<Todo, Array<Todo>>(url, 'POST', { data });
};
import { useMutation, useDatx } from '@datx/swr';
export const Todos: FC = () => {
const { data, error, mutate } = useDatx(todosQuery);
const [create, { status }] = useMutation(createTodo, {
onSuccess: async () => {
mutate();
},
});
// ...
};
Utils
SWR Client
fetchQuery
Takes in an expression as an argument and returns a promise with the response. Useful on server side for fetching data before rendering.
const client = createClient();
const todo = await client.fetchQuery(todosQuery);
requestSingle and requestCollection
Same as request
but with a bit more type safety.
const client = createClient();
const todo = await client.requestSingle('todos/1', 'GET', undefined); // returns SingleResponse
const todos = await client.requestCollection('todos', 'GET', undefined); // returns CollectionResponse
hydrate
type Fallback = Record<string, IRawResponse>
const fallback = {
'/api/v1/todos': rawResponse
}
<Hydrate fallback={fallback} />