Skip to content

Instantly share code, notes, and snippets.

@ksinas
Created March 10, 2022 15:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ksinas/388d5c1195a27f0549962df2d07ce571 to your computer and use it in GitHub Desktop.
Save ksinas/388d5c1195a27f0549962df2d07ce571 to your computer and use it in GitHub Desktop.
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';
import { useEffect } from 'react';
class PromiseContext {
resolved = false;
constructor() {
this.promise = new Promise((res, rej) => {
this.resolve = res;
this.reject = rej;
});
this.promise.then(() => {
this.resolved = true;
// silence the error
}, () => {});
}
}
const subscriptions = new Map();
const createComputation = (scope, method, args) => {
const promise = new PromiseContext();
const context = {
count: 0,
ready: false,
promise,
};
Tracker.nonreactive(() => {
Tracker.autorun(computation => {
computation.onStop(() => subscriptions.delete(scope));
context.computation = computation;
if (!method) {
context.ready = true;
promise.resolve(computation);
return;
}
const sub = Meteor.subscribe(method, args, {
onError: (err) => {
context.error = err;
promise.reject(err);
// give 5s until we let a new request occur
setTimeout(() => {
computation.stop();
}, 5000);
},
});
if (sub.ready()) {
context.ready = true;
promise.resolve(computation);
// setup self-destruction in case component has been unmounted
// while loading and hook has never been called
context.destroyHandle = setTimeout(() => {
computation.stop();
}, 3000);
}
});
});
subscriptions.set(scope, context);
return context;
};
const useSubscribeSuspend = (method, args) => {
const scope = JSON.stringify([method, args]);
let subscription = subscriptions.get(scope);
if (!subscription) {
subscription = createComputation(scope, method, args);
}
if (subscription.error) {
throw subscription.error;
}
if (!subscription.ready) {
throw subscription.promise.promise;
}
useEffect(() => {
clearTimeout(subscription.destroyHandle);
subscription.count += 1;
return () => {
subscription.count -= 1;
if (!subscription.count) {
subscription.computation.stop();
}
};
}, [subscription]);
};
export default useSubscribeSuspend;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment