-
Notifications
You must be signed in to change notification settings - Fork 169
Attempt to make the useSubscription hook simpler by removing reactivity #305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,62 +1,48 @@ | ||
| import { Meteor } from 'meteor/meteor' | ||
| import { Mongo } from 'meteor/mongo' | ||
| import { Tracker } from 'meteor/tracker' | ||
| import { useEffect, useMemo, useReducer, useRef, DependencyList } from 'react' | ||
| import { useEffect, useMemo, useReducer, useState, DependencyList } from 'react' | ||
|
|
||
| const fur = (x: number): number => x + 1 | ||
| const useForceUpdate = () => useReducer(fur, 0)[1] | ||
|
|
||
| const useSubscriptionClient = (factory: () => Meteor.SubscriptionHandle | void, deps: DependencyList= []) => { | ||
| const forceUpdate = useForceUpdate() | ||
| const { current: refs } = useRef<{ | ||
| handle?: Meteor.SubscriptionHandle, | ||
| updateOnReady: boolean | ||
| }>({ | ||
| handle: { | ||
| stop () { | ||
| refs.handle?.stop() | ||
| }, | ||
| ready () { | ||
| refs.updateOnReady = true | ||
| return refs.handle?.ready() | ||
| } | ||
| }, | ||
| updateOnReady: false | ||
| }) | ||
| const useSubscriptionClient = ( | ||
| name: string | false, | ||
| args: any[] | ||
| ): void | Meteor.SubscriptionHandle => { | ||
| const [subscription, setSubscription] = useState<Meteor.SubscriptionHandle>() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should put that in state : we don't need to rerender when the subscription changes A useRef should be enough ?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, that's a really good point. We don't need a rerender for a changing subscription. The ready state might change, though. I'll change it to a ref and see if I can get the ready state to invalidate immediately as well.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the ready state might change, that is handled by the ready() func being a reactive source.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah yes, that means the stub ready() getter we initially return must be reactive too :-/
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I incorporated the changes in 76943f7. The problem with ready(), is that it will always lag behind one render. So when changing the deps, it will still return the previous subscription's status for one render. I have a suggestion on how to fix that, I'll push that in the next commit.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| useEffect(() => { | ||
| if (!name) { | ||
| return setSubscription( null ) | ||
| } | ||
|
|
||
| // Use Tracker.nonreactive in case we are inside a Tracker Computation. | ||
| // This can happen if someone calls `ReactDOM.render` inside a Computation. | ||
| // In that case, we want to opt out of the normal behavior of nested | ||
| // Computations, where if the outer one is invalidated or stopped, | ||
| // it stops the inner one. | ||
| const computation = Tracker.nonreactive(() => ( | ||
| Tracker.autorun(() => { | ||
| refs.handle = factory() | ||
| if (!refs.handle) return | ||
| if (refs.updateOnReady && refs.handle.ready()) { | ||
| forceUpdate() | ||
| } | ||
| setSubscription( Meteor.subscribe( name, ...args ) ) | ||
| }) | ||
| )) | ||
|
|
||
| return () => { | ||
| computation.stop() | ||
| } | ||
| }, deps) | ||
| return () => computation.stop() | ||
| }, [name, ...args]) | ||
|
|
||
| return refs.handle | ||
| return subscription | ||
|
rijk marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| const useSubscriptionServer = (): Meteor.SubscriptionHandle => ({ | ||
| stop() {}, | ||
| ready() { return true } | ||
| }) | ||
|
|
||
| export const useSubscription = (factory: () => Meteor.SubscriptionHandle | void, deps: DependencyList = []) => ( | ||
| export const useSubscription = (name: string | false, ...args: any[]) => ( | ||
| Meteor.isServer | ||
| ? useSubscriptionServer() | ||
| : useSubscriptionClient(factory, deps) | ||
| : useSubscriptionClient(name, args) | ||
| ) | ||
|
|
||
| const useCursorClient = <T = any>(factory: () => Mongo.Cursor<T>, deps: DependencyList = []) => { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.