Skip to content

Canaan Query

@canaan/query

Tiny fetching, powered by Canaan.

No over-fetching. No surprises. No chaos.

One Query per thing you fetch
You call fetch() when you want data
Subscribe to exactly what you need

1) Make a query

import { Query } from '@canaan/query';

export const results = new Query('results', fetcher);

ok

we already have fetcher for everything we need. Less changes.

2) Fetch, Just that.

No handling needed for loading or data state. Just handle errors.
results.isLoading(); // false
results.data(); // undefined

await results.fetch();

results.isLoading(); // false
results.data(); // [... your results]

3) Subscribe in React


import { useSubscribe } from '@canaan/query/react';
import { EViewStatus } from '@canaan/paint/constants';
import { results } from './queries';
import { getView } from './model';

export function Results() {
const { data } = useSubscribe(results.data);
const { data: error } = useSubscribe(results.error);
const { data: isLoading } = useSubscribe(results.isLoading);
const view = getView(data, error, isLoading);

return (
<Switch type={view}>
<Case is={EViewStatus.loading}>
<LoadingView />
</Case>
<Case is={EViewStatus.error}>
<ErrorView />
</Case>
<Case is={EViewStatus.empty}>
<EmptyView />
</Case>
<Case is={EViewStatus.idle}>
<DataView />
</Case>
</Switch>
);
}

Less bloated approach - (A recommendation):

import { EViewStatus } from '@canaan/paint/constants';
import { useSubscribe } from '@canaan/query/react';
import { results } from './queries';
import { getView } from './model';

export function Results() {
const { data: state } = useSubscribe(results.state);
const view = getView(state);

return (
<Switch type={view}>
<Case is={EViewStatus.loading}>
<LoadingView />
</Case>
<Case is={EViewStatus.error}>
<ErrorView />
</Case>
<Case is={EViewStatus.empty}>
<EmptyView />
</Case>
<Case is={EViewStatus.idle}>
<DataView />
</Case>
</Switch>
);
}

4) Optimistic update (only if needed)

results.setData([1, 2, 3]); // instantly reflect
// …later
await results.fetch(); // reconcile with server

API (that’s it)

new Query<T>(key: string, fetcher: () => Promise<T>);

query.fetch(): Promise<T>;
query.data(): T | undefined;
query.isLoading(): boolean;
query.error(): unknown | undefined;
query.setData(next: T | ((prev: T | undefined) => T)): void;

Why this?

No auto-refetches
No config maze
One key = one truth

Want to print your doc?
This is not the way.
Try clicking the ··· in the right corner or using a keyboard shortcut (
CtrlP
) instead.