Skip to content

Instantly share code, notes, and snippets.

@Talor-A
Created June 30, 2021 02:29
Show Gist options
  • Save Talor-A/a1664f0ac43283ecd6997acabf6ed403 to your computer and use it in GitHub Desktop.
Save Talor-A/a1664f0ac43283ecd6997acabf6ed403 to your computer and use it in GitHub Desktop.
useSubscribe suspense
import { ReadTransaction, Replicache } from "replicache/out/replicache";
class Deferred<T> {
promise: Promise<T>;
resolve!: (value: T | PromiseLike<T>) => void;
reject!: (reason?: any) => void;
constructor() {
this.promise = new Promise((resolve, reject) => {
this.reject = reject;
this.resolve = resolve;
});
}
}
export class SubscribeSuspender<T, E = Error> {
private deferred: Deferred<T>;
private _replicache: Replicache;
private _data: T | null = null;
private _error: E | null = null;
private status: "pending" | "success" | "error" = "pending";
constructor(
replicache: Replicache,
query: (tx: ReadTransaction) => Promise<T>
) {
this.deferred = new Deferred();
this._replicache = replicache;
this._replicache.subscribe(query, {
onData: (data) => {
this.deferred.resolve(data);
this.deferred.promise.then(() => {
this._data = data;
this._error = null;
this.status = "success";
});
},
onDone: () => {
console.log("onDone");
},
onError: (e) => {
this.status = "error";
this._error = e as E;
},
});
}
setData(newVal: T | null) {
this.status = "success";
}
get suspender() {
return this.deferred.promise;
}
read() {
console.log(`read:${this.status}`);
switch (this.status) {
case "pending":
throw this.suspender;
case "error":
return [null, this._error] as [null, E];
default:
return [this._data, null] as [T, null];
}
}
}
export const useSubscribeSuspense = <T>(
query: (tx: ReadTransaction) => Promise<T>
) => {
const rep = useReplicache();
const mgr = useRef(new SubscribeSuspender<T>(rep, query));
return mgr.current.read();
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment