Skip to content

Instantly share code, notes, and snippets.

@copleykj
Last active January 8, 2022 23:14
Show Gist options
  • Save copleykj/19886511fc10fac3c990061c8f8bbf23 to your computer and use it in GitHub Desktop.
Save copleykj/19886511fc10fac3c990061c8f8bbf23 to your computer and use it in GitHub Desktop.
Grapher Hooks
import { useState, useEffect, useRef } from 'react';
import { useTracker } from 'meteor/react-meteor-data';
import { Grapher } from 'meteor/cultofcoders:grapher';
import { Meteor } from 'meteor/meteor';
interface QueryInfo<T> {
loading: boolean
ready: boolean
data: T[]
error: Meteor.Error | null
}
interface QueryParams<T> {
query: Grapher.Query<T>
params?: any
}
const withReactiveQuery = function <T>({ query, params = {} }: QueryParams<T>): QueryInfo<T> {
const [subscriptionError, setSubscriptionError] = useState<Meteor.Error | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [isReady, setIsReady] = useState<boolean>(false);
const subscriptionHandle = useRef<Meteor.SubscriptionHandle | undefined>(undefined);
const queryRef = useRef<Grapher.Query<T> | undefined>(undefined);
const depends = Object.values(params);
const queryInfo: QueryInfo<T> = useTracker(() => {
let data: QueryInfo<T>['data'] = [];
useEffect(() => {
queryRef.current = query.clone(params);
console.log('using effect');
setSubscriptionError(null);
setIsLoading(true);
setIsReady(false);
subscriptionHandle.current = queryRef.current?.subscribe({
onStop (err) {
if (typeof err !== 'undefined') {
console.log('subscriptiong stopped');
setSubscriptionError(err);
}
setIsLoading(false);
},
onReady () {
setSubscriptionError(null);
setIsLoading(false);
setIsReady(true);
},
});
return () => { subscriptionHandle?.current?.stop(); };
}, depends);
if (typeof queryRef.current !== 'undefined' && isReady) {
data = queryRef.current.fetch();
}
return {
loading: isLoading,
ready: isReady,
data,
error: subscriptionError,
};
});
return queryInfo;
};
export default withReactiveQuery;
import { useState, useEffect, useMemo } from 'react';
import { Grapher } from 'meteor/cultofcoders:grapher';
import { Meteor } from 'meteor/meteor';
interface QueryInfo<T> {
loading: boolean
refetch: () => void
data: T[]
count: number | undefined
error: Meteor.Error | null
}
interface FetchConfig {
loadOnRefetch?: boolean
fetchTotal?: boolean
}
interface QueryParams<T> {
query: Grapher.Query<T>
params?: any
config?: FetchConfig
}
const withStaticQuery = function <T>({ query, params, config: { loadOnRefetch = true, fetchTotal = false } = {} }: QueryParams<T>): QueryInfo<T> {
const [fetchError, setfetchError] = useState<Meteor.Error | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [data, setData] = useState<T[]>([]);
const [count, setCount] = useState<number | undefined>(undefined);
const depends = Object.values(params);
const { limit, skip, ...paramsWithoutPagination } = params;
const newQuery = useMemo(() => { return query.clone(params); }, depends);
const countQuery = useMemo(() => { return query.clone(paramsWithoutPagination); }, depends);
const fetch = async (): Promise<void> => {
let data;
let count;
try {
data = await newQuery.fetchSync();
if (fetchTotal) {
count = await countQuery.getCountSync();
}
setData(data);
setCount(count);
setfetchError(null);
} catch (error) {
setData([]);
setfetchError(error);
setCount(undefined);
} finally {
setIsLoading(false);
}
};
const refetch = (): void => {
if (loadOnRefetch) {
setIsLoading(true);
}
void fetch();
};
useEffect(() => {
setfetchError(null);
setIsLoading(true);
void fetch();
}, depends);
return {
loading: isLoading,
refetch,
data,
count,
error: fetchError,
};
};
export default withStaticQuery;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment