From 879b64d65fa5c2f044c6b67ff061e5710af081e6 Mon Sep 17 00:00:00 2001 From: Rijk van Wel Date: Tue, 3 Nov 2020 11:44:11 +0100 Subject: [PATCH 1/3] Attempt to make the useSubscription hook simpler by removing reactivity --- packages/react-mongo/react-mongo.ts | 46 ++++++++++------------------- 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/packages/react-mongo/react-mongo.ts b/packages/react-mongo/react-mongo.ts index 6d2538be..47449a8f 100644 --- a/packages/react-mongo/react-mongo.ts +++ b/packages/react-mongo/react-mongo.ts @@ -1,30 +1,22 @@ 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() 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 @@ -32,20 +24,14 @@ const useSubscriptionClient = (factory: () => Meteor.SubscriptionHandle | void, // 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 } const useSubscriptionServer = (): Meteor.SubscriptionHandle => ({ @@ -53,10 +39,10 @@ const useSubscriptionServer = (): Meteor.SubscriptionHandle => ({ 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 = (factory: () => Mongo.Cursor, deps: DependencyList = []) => { From 76943f7d144c6fa773cfe18e16f526b150c619dd Mon Sep 17 00:00:00 2001 From: Rijk van Wel Date: Tue, 3 Nov 2020 13:48:05 +0100 Subject: [PATCH 2/3] Consistent return signature, useRef for subscription --- packages/react-mongo/react-mongo.ts | 25 ++++++++++++++++----- packages/react-mongo/types/react-mongo.d.ts | 3 +-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/packages/react-mongo/react-mongo.ts b/packages/react-mongo/react-mongo.ts index 47449a8f..abd51aa9 100644 --- a/packages/react-mongo/react-mongo.ts +++ b/packages/react-mongo/react-mongo.ts @@ -1,7 +1,14 @@ import { Meteor } from 'meteor/meteor' import { Mongo } from 'meteor/mongo' import { Tracker } from 'meteor/tracker' -import { useEffect, useMemo, useReducer, useState, DependencyList } from 'react' +import { + useEffect, + useMemo, + useReducer, + useRef, + useCallback, + DependencyList, +} from 'react' const fur = (x: number): number => x + 1 const useForceUpdate = () => useReducer(fur, 0)[1] @@ -9,12 +16,13 @@ const useForceUpdate = () => useReducer(fur, 0)[1] const useSubscriptionClient = ( name: string | false, args: any[] -): void | Meteor.SubscriptionHandle => { - const [subscription, setSubscription] = useState() +) => { + const subscription = useRef() useEffect(() => { if (!name) { - return setSubscription( null ) + subscription.current = null + return } // Use Tracker.nonreactive in case we are inside a Tracker Computation. @@ -24,14 +32,19 @@ const useSubscriptionClient = ( // it stops the inner one. const computation = Tracker.nonreactive(() => ( Tracker.autorun(() => { - setSubscription( Meteor.subscribe( name, ...args ) ) + subscription.current = Meteor.subscribe( name, ...args ) }) )) return () => computation.stop() }, [name, ...args]) - return subscription + return useCallback( + () => { + return subscription.current?.ready() + }, + [name, ...args] + ) } const useSubscriptionServer = (): Meteor.SubscriptionHandle => ({ diff --git a/packages/react-mongo/types/react-mongo.d.ts b/packages/react-mongo/types/react-mongo.d.ts index f09637bb..2ae352cc 100644 --- a/packages/react-mongo/types/react-mongo.d.ts +++ b/packages/react-mongo/types/react-mongo.d.ts @@ -1,10 +1,9 @@ -import { Meteor } from 'meteor/meteor'; import { Mongo } from 'meteor/mongo'; import { DependencyList } from 'react'; declare type UseSubscriptionOptions = { deps?: DependencyList; updateOnReady?: boolean; }; -export declare const useSubscription: (factory: () => Meteor.SubscriptionHandle | void, deps?: DependencyList | UseSubscriptionOptions) => void; +export declare const useSubscription: (name: string | false, args: any[]) => () => boolean; export declare const useCursor: (factory: () => Mongo.Cursor, deps?: DependencyList) => Mongo.Cursor; export {}; From e37ba55e0507ad1b80afd3fcfa6e3a551fe4d1a3 Mon Sep 17 00:00:00 2001 From: Rijk van Wel Date: Tue, 3 Nov 2020 13:55:29 +0100 Subject: [PATCH 3/3] =?UTF-8?q?Fix=20previous=20subscription=E2=80=99s=20s?= =?UTF-8?q?tatus=20returned=20after=20switching=20args?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-mongo/react-mongo.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/react-mongo/react-mongo.ts b/packages/react-mongo/react-mongo.ts index abd51aa9..c2a4178d 100644 --- a/packages/react-mongo/react-mongo.ts +++ b/packages/react-mongo/react-mongo.ts @@ -33,6 +33,8 @@ const useSubscriptionClient = ( const computation = Tracker.nonreactive(() => ( Tracker.autorun(() => { subscription.current = Meteor.subscribe( name, ...args ) + // @ts-ignore this is just an internal thing + subscription.current.deps = { name, args } }) )) @@ -41,7 +43,17 @@ const useSubscriptionClient = ( return useCallback( () => { - return subscription.current?.ready() + if (subscription.current) { + // @ts-ignore + const { deps } = subscription.current + if (deps.name === name && deps.args === args) { + return subscription.current.ready() + } else { + // Prevented returning the previous subscription's status + } + } + + return false }, [name, ...args] )