Skip to content

Commit 98d80d2

Browse files
committed
Voidable sub factory, reactive ready, and a Readme
1 parent d94b254 commit 98d80d2

File tree

3 files changed

+77
-11
lines changed

3 files changed

+77
-11
lines changed

packages/react-mongo/README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,44 @@
11
meteor/react-mongo
22
==================
33

4+
```
5+
meteor add meteor/react-mongo
6+
```
7+
48
A set of hooks for using Meteor's Mini Mongo Collections and pub/sub.
9+
10+
There are two hooks
11+
12+
| Hook | Function
13+
| ---- | --------
14+
| useSubscription | Used to set up a Meteor subscription. In SSR, this hook is responsible for capturing data to be sent to the client for hydration.
15+
| useCursor | Manages the lifecycle of a Mongo Cursor
16+
17+
Both methods accept a factory method, and deps.
18+
19+
## useSubscription(factory, deps)
20+
21+
`useSubscription` takes a factory method, which should return a subscription handle, and a deps array. It can also return `void` to conditionally set up no subscription. The hook returns a subscription handle with a reactive `ready` method.
22+
23+
Invoking the `ready()` handle method will cause the hook to update react when the subscription becomes available.
24+
25+
### Example
26+
27+
```jsx
28+
import React from 'react'
29+
import { useSubscription } from 'meteor/react-mongo'
30+
31+
const MyComponent = ({ id = null }) => {
32+
const subscription = useSubscription(() => {
33+
if (id) return Meteor.subscribe(id)
34+
}, [id])
35+
36+
return <div>
37+
{
38+
subscription.ready()
39+
? 'content ready'
40+
: 'loading...'
41+
}
42+
</div>
43+
}
44+
```

packages/react-mongo/react-mongo.ts

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,54 @@ import { useEffect, useMemo, useReducer, useRef, DependencyList } from 'react'
66
const fur = (x: number): number => x + 1
77
const useForceUpdate = () => useReducer(fur, 0)[1]
88

9-
const useSubscriptionClient = (factory: () => Meteor.SubscriptionHandle, deps: DependencyList = []) => {
9+
const useSubscriptionClient = (factory: () => Meteor.SubscriptionHandle | void, deps: DependencyList= []) => {
1010
const forceUpdate = useForceUpdate()
11-
const subscription = useRef<Meteor.SubscriptionHandle>({
12-
stop() {},
13-
ready: () => false
11+
const { current: refs } = useRef<{
12+
handle?: Meteor.SubscriptionHandle,
13+
updateOnReady: boolean
14+
}>({
15+
handle: {
16+
stop () {
17+
refs.handle?.stop()
18+
},
19+
ready () {
20+
refs.updateOnReady = true
21+
return refs.handle?.ready()
22+
}
23+
},
24+
updateOnReady: false
1425
})
1526

1627
useEffect(() => {
17-
const computation = Tracker.autorun(() => {
18-
subscription.current = factory()
19-
if (subscription.current.ready()) forceUpdate()
20-
})
28+
// Use Tracker.nonreactive in case we are inside a Tracker Computation.
29+
// This can happen if someone calls `ReactDOM.render` inside a Computation.
30+
// In that case, we want to opt out of the normal behavior of nested
31+
// Computations, where if the outer one is invalidated or stopped,
32+
// it stops the inner one.
33+
const computation = Tracker.nonreactive(() => (
34+
Tracker.autorun(() => {
35+
refs.handle = factory()
36+
if (!refs.handle) return
37+
if (refs.updateOnReady && refs.handle.ready()) {
38+
forceUpdate()
39+
}
40+
})
41+
))
2142

2243
return () => {
2344
computation.stop()
2445
}
2546
}, deps)
2647

27-
return subscription.current
48+
return refs.handle
2849
}
2950

3051
const useSubscriptionServer = (): Meteor.SubscriptionHandle => ({
3152
stop() {},
3253
ready() { return true }
3354
})
3455

35-
export const useSubscription = (factory: () => Meteor.SubscriptionHandle, deps: DependencyList = []) => (
56+
export const useSubscription = (factory: () => Meteor.SubscriptionHandle | void, deps: DependencyList = []) => (
3657
Meteor.isServer
3758
? useSubscriptionServer()
3859
: useSubscriptionClient(factory, deps)
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { Meteor } from 'meteor/meteor';
22
import { Mongo } from 'meteor/mongo';
33
import { DependencyList } from 'react';
4-
export declare const useSubscription: (factory: () => Meteor.SubscriptionHandle, deps?: DependencyList) => Meteor.SubscriptionHandle;
4+
declare type UseSubscriptionOptions = {
5+
deps?: DependencyList;
6+
updateOnReady?: boolean;
7+
};
8+
export declare const useSubscription: (factory: () => Meteor.SubscriptionHandle | void, deps?: DependencyList | UseSubscriptionOptions) => void;
59
export declare const useCursor: <T = any>(factory: () => Mongo.Cursor<T>, deps?: DependencyList) => Mongo.Cursor<T>;
10+
export {};

0 commit comments

Comments
 (0)