Created
March 10, 2022 15:39
-
-
Save ksinas/388d5c1195a27f0549962df2d07ce571 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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