Skip to content

Instantly share code, notes, and snippets.

@dgeb
Last active March 2, 2022 20:50
Show Gist options
  • Save dgeb/42fbe4aebabe578707fa9c21c957ade6 to your computer and use it in GitHub Desktop.
Save dgeb/42fbe4aebabe578707fa9c21c957ade6 to your computer and use it in GitHub Desktop.
React hooks for Orbit.js
import type {QueryOrExpressions, RequestOptions} from '@orbit/data';
import {RecordQueryBuilder, RecordQueryExpression} from '@orbit/records';
export type QueryDispatch = (
queryOrExpressions: QueryOrExpressions<
RecordQueryExpression,
RecordQueryBuilder
>,
queryOptions?: RequestOptions,
queryId?: string,
) => void;
import {useEffect, useState} from 'react';
import {
buildQuery as bq,
RequestOptions,
QueryOrExpressions,
} from '@orbit/data';
import type {
RecordQueryBuilder,
RecordQueryResult,
RecordQuery,
RecordQueryExpression,
} from '@orbit/records';
import type {QueryDispatch} from './queries';
export interface AsyncQueryable {
query(
queryOrExpressions: QueryOrExpressions<
RecordQueryExpression,
RecordQueryBuilder
>,
options?: RequestOptions,
id?: string,
): Promise<RecordQueryResult>;
queryBuilder: RecordQueryBuilder;
}
export default function useQuery(
queryable: AsyncQueryable,
queryOrExpressions: QueryOrExpressions<
RecordQueryExpression,
RecordQueryBuilder
>,
queryOptions?: RequestOptions,
queryId?: string,
): {
data: RecordQueryResult | undefined;
error: Error | undefined;
loading: boolean;
retry: () => void;
reset: QueryDispatch;
} {
const [query, setQuery] = useState(
buildQuery(queryOrExpressions, queryOptions, queryId),
);
const [data, setData] = useState<RecordQueryResult | undefined>();
const [error, setError] = useState<Error | undefined>();
const [loading, setLoading] = useState(true);
function buildQuery(
queryOrExpressions: QueryOrExpressions<
RecordQueryExpression,
RecordQueryBuilder
>,
queryOptions?: RequestOptions,
queryId?: string,
): RecordQuery {
return bq(
queryOrExpressions,
queryOptions,
queryId,
queryable.queryBuilder,
);
}
async function performQuery() {
if (query) {
try {
setData(await queryable.query(query));
} catch (e) {
setError(e);
} finally {
setLoading(false);
}
} else if (data !== undefined) {
setData(undefined);
}
}
const reset = (
queryOrExpressions: QueryOrExpressions<
RecordQueryExpression,
RecordQueryBuilder
>,
queryOptions?: RequestOptions,
queryId?: string,
) => {
setLoading(true);
setQuery(buildQuery(queryOrExpressions, queryOptions, queryId));
};
const retry = () => {
setLoading(true);
performQuery();
};
useEffect(() => {
performQuery();
}, [query]);
return {data, error, loading, retry, reset};
}
import {useEffect, useState} from 'react';
import type {SyncRecordCache} from '@orbit/record-cache';
import {
buildQuery as bq,
QueryOrExpressions,
RequestOptions,
} from '@orbit/data';
import type {
RecordQuery,
RecordQueryBuilder,
RecordQueryExpression,
RecordQueryResult,
} from '@orbit/records';
import type {QueryDispatch} from './shared/queries';
export default function useSyncLiveQuery<T extends RecordQueryResult>(
queryable: SyncRecordCache,
queryOrExpressions: QueryOrExpressions<
RecordQueryExpression,
RecordQueryBuilder
>,
queryOptions?: RequestOptions,
queryId?: string,
): {
data: T | undefined;
error: Error | undefined;
reset: QueryDispatch;
} {
const [query, setQuery] = useState(
buildQuery(queryOrExpressions, queryOptions, queryId),
);
const [data, setData] = useState<RecordQueryResult | undefined>();
const [error, setError] = useState();
function buildQuery(
queryOrExpressions: QueryOrExpressions<
RecordQueryExpression,
RecordQueryBuilder
>,
queryOptions?: RequestOptions,
queryId?: string,
): RecordQuery {
return bq(
queryOrExpressions,
queryOptions,
queryId,
queryable.queryBuilder,
);
}
function performLiveQuery() {
if (query) {
try {
setData(queryable.query(query));
} catch (e) {
setError(e);
}
let unsubscribe = queryable.liveQuery(query).subscribe(lq => {
setData(lq.query() as T);
});
return () => {
unsubscribe();
};
} else if (data !== undefined) {
setData(undefined);
}
}
useEffect(() => performLiveQuery(), [query]);
const reset = (
queryOrExpressions: QueryOrExpressions<
RecordQueryExpression,
RecordQueryBuilder
>,
queryOptions?: RequestOptions,
queryId?: string,
) => {
setQuery(buildQuery(queryOrExpressions, queryOptions, queryId));
};
return {data: data as T, error, reset};
}
import {useEffect, useState} from 'react';
import {
buildQuery as bq,
QueryOrExpressions,
RequestOptions,
} from '@orbit/data';
import type {
RecordQueryResult,
RecordQueryBuilder,
RecordQuery,
RecordQueryExpression,
} from '@orbit/records';
import type {QueryDispatch} from './queries';
export interface SyncQueryable {
query(
queryOrExpressions: QueryOrExpressions<
RecordQueryExpression,
RecordQueryBuilder
>,
options?: RequestOptions,
id?: string,
): RecordQueryResult;
queryBuilder: RecordQueryBuilder;
}
export default function useSyncQuery(
queryable: SyncQueryable,
queryOrExpressions: QueryOrExpressions<
RecordQueryExpression,
RecordQueryBuilder
>,
queryOptions?: RequestOptions,
queryId?: string,
): {
data: RecordQueryResult | undefined;
error: Error | undefined;
retry: () => void;
reset: QueryDispatch;
} {
const [query, setQuery] = useState(
buildQuery(queryOrExpressions, queryOptions, queryId),
);
const [data, setData] = useState<RecordQueryResult | undefined>();
const [error, setError] = useState();
function buildQuery(
queryOrExpressions: QueryOrExpressions<
RecordQueryExpression,
RecordQueryBuilder
>,
queryOptions?: RequestOptions,
queryId?: string,
): RecordQuery {
return bq(
queryOrExpressions,
queryOptions,
queryId,
queryable.queryBuilder,
);
}
function performQuery() {
if (query) {
try {
setData(queryable.query(query));
} catch (e) {
setError(e);
}
} else if (data !== undefined) {
setData(undefined);
}
}
const reset = (
queryOrExpressions: QueryOrExpressions<
RecordQueryExpression,
RecordQueryBuilder
>,
queryOptions?: RequestOptions,
queryId?: string,
) => {
setQuery(buildQuery(queryOrExpressions, queryOptions, queryId));
};
const retry = () => performQuery();
useEffect(() => performQuery(), [query]);
return {data, error, retry, reset};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment