Comparing version 3.0.0-2 to 3.0.0-3
@@ -1,4 +0,4 @@ | ||
import { Observable } from 'rxjs'; | ||
import type { Observable } from 'rxjs'; | ||
export declare function useObservable<ObservableType extends Observable<any>>(observable: ObservableType, initialValue?: UnboxObservable<ObservableType> | (() => UnboxObservable<ObservableType>)): UnboxObservable<ObservableType>; | ||
declare type UnboxObservable<T> = T extends Observable<infer U> ? U : never; | ||
export {}; |
@@ -10,12 +10,2 @@ "use strict"; | ||
var cache = new WeakMap(); | ||
function getOrCreateStore(inputObservable, initialValue) { | ||
if (!cache.has(inputObservable)) { | ||
var entry_1 = { currentValue: initialValue }; | ||
entry_1.observable = inputObservable.pipe((0, operators_1.shareReplay)({ refCount: true, bufferSize: 1 }), (0, operators_1.tap)(function (value) { return (entry_1.currentValue = value); })); | ||
// Eagerly subscribe to sync set `entry.currentValue` to what the observable returns | ||
entry_1.subscription = entry_1.observable.subscribe(); | ||
cache.set(inputObservable, entry_1); | ||
} | ||
return cache.get(inputObservable); | ||
} | ||
function useObservable(observable, initialValue) { | ||
@@ -33,39 +23,28 @@ /** | ||
}, [initialValue]); | ||
var _a = (0, react_1.useMemo)(function () { | ||
var store = getOrCreateStore(observable, initialValueRef.current); | ||
if (store.subscription.closed) { | ||
store.subscription = store.observable.subscribe(); | ||
var store = (0, react_1.useMemo)(function () { | ||
if (!cache.has(observable)) { | ||
var entry_1 = { | ||
snapshot: initialValueRef.current, | ||
}; | ||
entry_1.observable = observable.pipe((0, operators_1.shareReplay)({ refCount: true, bufferSize: 1 }), (0, operators_1.tap)(function (value) { return (entry_1.snapshot = value); })); | ||
// Eagerly subscribe to sync set `entry.currentValue` to what the observable returns, and keep the observable alive until the component unmounts. | ||
entry_1.subscription = entry_1.observable.subscribe(); | ||
cache.set(observable, entry_1); | ||
} | ||
return [ | ||
function getSnapshot() { | ||
// @TODO: perf opt opportunity: we could do `store.subscription.unsubscribe()` here to clear up some memory, as this subscription is only needed to provide a sync initialValue. | ||
return store.currentValue; | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
var instance = cache.get(observable); | ||
if (instance.subscription.closed) { | ||
instance.subscription = instance.observable.subscribe(); | ||
} | ||
return { | ||
subscribe: function (onStoreChange) { | ||
var subscription = instance.observable.subscribe(onStoreChange); | ||
instance.subscription.unsubscribe(); | ||
return function () { return subscription.unsubscribe(); }; | ||
}, | ||
function subscribe(callback) { | ||
// @TODO: perf opt opportunity: we could do `store.subscription.unsubscribe()` here as we only need 1 subscription active to keep the observer alive | ||
var sub = store.observable.subscribe(callback); | ||
return function () { | ||
sub.unsubscribe(); | ||
}; | ||
}, | ||
]; | ||
}, [observable]), getSnapshot = _a[0], subscribe = _a[1]; | ||
var shouldRestoreSubscriptionRef = (0, react_1.useRef)(false); | ||
(0, react_1.useEffect)(function () { | ||
var store = getOrCreateStore(observable, initialValueRef.current); | ||
if (shouldRestoreSubscriptionRef.current) { | ||
if (store.subscription.closed) { | ||
store.subscription = store.observable.subscribe(); | ||
} | ||
shouldRestoreSubscriptionRef.current = false; | ||
} | ||
return function () { | ||
// React StrictMode will call effects as `setup + teardown + setup` thus we can't trust this callback as "react is about to unmount" | ||
// Tracking this ref lets us set the subscription back up on the next `setup` call if needed, and if it really did unmounted then all is well | ||
shouldRestoreSubscriptionRef.current = !store.subscription.closed; | ||
store.subscription.unsubscribe(); | ||
getSnapshot: function () { return instance.snapshot; }, | ||
}; | ||
}, [observable]); | ||
return (0, react_1.useSyncExternalStore)(subscribe, getSnapshot); | ||
return (0, react_1.useSyncExternalStore)(store.subscribe, store.getSnapshot); | ||
} | ||
exports.useObservable = useObservable; |
@@ -1,4 +0,4 @@ | ||
import { Observable } from 'rxjs'; | ||
import type { Observable } from 'rxjs'; | ||
export declare function useObservable<ObservableType extends Observable<any>>(observable: ObservableType, initialValue?: UnboxObservable<ObservableType> | (() => UnboxObservable<ObservableType>)): UnboxObservable<ObservableType>; | ||
declare type UnboxObservable<T> = T extends Observable<infer U> ? U : never; | ||
export {}; |
@@ -7,12 +7,2 @@ import { useEffect, useMemo, useRef, useSyncExternalStore } from 'react'; | ||
const cache = new WeakMap(); | ||
function getOrCreateStore(inputObservable, initialValue) { | ||
if (!cache.has(inputObservable)) { | ||
const entry = { currentValue: initialValue }; | ||
entry.observable = inputObservable.pipe(shareReplay({ refCount: true, bufferSize: 1 }), tap(value => (entry.currentValue = value))); | ||
// Eagerly subscribe to sync set `entry.currentValue` to what the observable returns | ||
entry.subscription = entry.observable.subscribe(); | ||
cache.set(inputObservable, entry); | ||
} | ||
return cache.get(inputObservable); | ||
} | ||
export function useObservable(observable, initialValue) { | ||
@@ -30,38 +20,27 @@ /** | ||
}, [initialValue]); | ||
const [getSnapshot, subscribe] = useMemo(() => { | ||
const store = getOrCreateStore(observable, initialValueRef.current); | ||
if (store.subscription.closed) { | ||
store.subscription = store.observable.subscribe(); | ||
const store = useMemo(() => { | ||
if (!cache.has(observable)) { | ||
const entry = { | ||
snapshot: initialValueRef.current, | ||
}; | ||
entry.observable = observable.pipe(shareReplay({ refCount: true, bufferSize: 1 }), tap(value => (entry.snapshot = value))); | ||
// Eagerly subscribe to sync set `entry.currentValue` to what the observable returns, and keep the observable alive until the component unmounts. | ||
entry.subscription = entry.observable.subscribe(); | ||
cache.set(observable, entry); | ||
} | ||
return [ | ||
function getSnapshot() { | ||
// @TODO: perf opt opportunity: we could do `store.subscription.unsubscribe()` here to clear up some memory, as this subscription is only needed to provide a sync initialValue. | ||
return store.currentValue; | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
const instance = cache.get(observable); | ||
if (instance.subscription.closed) { | ||
instance.subscription = instance.observable.subscribe(); | ||
} | ||
return { | ||
subscribe: (onStoreChange) => { | ||
const subscription = instance.observable.subscribe(onStoreChange); | ||
instance.subscription.unsubscribe(); | ||
return () => subscription.unsubscribe(); | ||
}, | ||
function subscribe(callback) { | ||
// @TODO: perf opt opportunity: we could do `store.subscription.unsubscribe()` here as we only need 1 subscription active to keep the observer alive | ||
const sub = store.observable.subscribe(callback); | ||
return () => { | ||
sub.unsubscribe(); | ||
}; | ||
}, | ||
]; | ||
}, [observable]); | ||
const shouldRestoreSubscriptionRef = useRef(false); | ||
useEffect(() => { | ||
const store = getOrCreateStore(observable, initialValueRef.current); | ||
if (shouldRestoreSubscriptionRef.current) { | ||
if (store.subscription.closed) { | ||
store.subscription = store.observable.subscribe(); | ||
} | ||
shouldRestoreSubscriptionRef.current = false; | ||
} | ||
return () => { | ||
// React StrictMode will call effects as `setup + teardown + setup` thus we can't trust this callback as "react is about to unmount" | ||
// Tracking this ref lets us set the subscription back up on the next `setup` call if needed, and if it really did unmounted then all is well | ||
shouldRestoreSubscriptionRef.current = !store.subscription.closed; | ||
store.subscription.unsubscribe(); | ||
getSnapshot: () => instance.snapshot, | ||
}; | ||
}, [observable]); | ||
return useSyncExternalStore(subscribe, getSnapshot); | ||
return useSyncExternalStore(store.subscribe, store.getSnapshot); | ||
} |
@@ -1,4 +0,4 @@ | ||
import { Observable } from 'rxjs'; | ||
import type { Observable } from 'rxjs'; | ||
export declare function useObservable<ObservableType extends Observable<any>>(observable: ObservableType, initialValue?: UnboxObservable<ObservableType> | (() => UnboxObservable<ObservableType>)): UnboxObservable<ObservableType>; | ||
declare type UnboxObservable<T> = T extends Observable<infer U> ? U : never; | ||
export {}; |
@@ -7,12 +7,2 @@ import { useEffect, useMemo, useRef, useSyncExternalStore } from 'react'; | ||
var cache = new WeakMap(); | ||
function getOrCreateStore(inputObservable, initialValue) { | ||
if (!cache.has(inputObservable)) { | ||
var entry_1 = { currentValue: initialValue }; | ||
entry_1.observable = inputObservable.pipe(shareReplay({ refCount: true, bufferSize: 1 }), tap(function (value) { return (entry_1.currentValue = value); })); | ||
// Eagerly subscribe to sync set `entry.currentValue` to what the observable returns | ||
entry_1.subscription = entry_1.observable.subscribe(); | ||
cache.set(inputObservable, entry_1); | ||
} | ||
return cache.get(inputObservable); | ||
} | ||
export function useObservable(observable, initialValue) { | ||
@@ -30,38 +20,27 @@ /** | ||
}, [initialValue]); | ||
var _a = useMemo(function () { | ||
var store = getOrCreateStore(observable, initialValueRef.current); | ||
if (store.subscription.closed) { | ||
store.subscription = store.observable.subscribe(); | ||
var store = useMemo(function () { | ||
if (!cache.has(observable)) { | ||
var entry_1 = { | ||
snapshot: initialValueRef.current, | ||
}; | ||
entry_1.observable = observable.pipe(shareReplay({ refCount: true, bufferSize: 1 }), tap(function (value) { return (entry_1.snapshot = value); })); | ||
// Eagerly subscribe to sync set `entry.currentValue` to what the observable returns, and keep the observable alive until the component unmounts. | ||
entry_1.subscription = entry_1.observable.subscribe(); | ||
cache.set(observable, entry_1); | ||
} | ||
return [ | ||
function getSnapshot() { | ||
// @TODO: perf opt opportunity: we could do `store.subscription.unsubscribe()` here to clear up some memory, as this subscription is only needed to provide a sync initialValue. | ||
return store.currentValue; | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
var instance = cache.get(observable); | ||
if (instance.subscription.closed) { | ||
instance.subscription = instance.observable.subscribe(); | ||
} | ||
return { | ||
subscribe: function (onStoreChange) { | ||
var subscription = instance.observable.subscribe(onStoreChange); | ||
instance.subscription.unsubscribe(); | ||
return function () { return subscription.unsubscribe(); }; | ||
}, | ||
function subscribe(callback) { | ||
// @TODO: perf opt opportunity: we could do `store.subscription.unsubscribe()` here as we only need 1 subscription active to keep the observer alive | ||
var sub = store.observable.subscribe(callback); | ||
return function () { | ||
sub.unsubscribe(); | ||
}; | ||
}, | ||
]; | ||
}, [observable]), getSnapshot = _a[0], subscribe = _a[1]; | ||
var shouldRestoreSubscriptionRef = useRef(false); | ||
useEffect(function () { | ||
var store = getOrCreateStore(observable, initialValueRef.current); | ||
if (shouldRestoreSubscriptionRef.current) { | ||
if (store.subscription.closed) { | ||
store.subscription = store.observable.subscribe(); | ||
} | ||
shouldRestoreSubscriptionRef.current = false; | ||
} | ||
return function () { | ||
// React StrictMode will call effects as `setup + teardown + setup` thus we can't trust this callback as "react is about to unmount" | ||
// Tracking this ref lets us set the subscription back up on the next `setup` call if needed, and if it really did unmounted then all is well | ||
shouldRestoreSubscriptionRef.current = !store.subscription.closed; | ||
store.subscription.unsubscribe(); | ||
getSnapshot: function () { return instance.snapshot; }, | ||
}; | ||
}, [observable]); | ||
return useSyncExternalStore(subscribe, getSnapshot); | ||
return useSyncExternalStore(store.subscribe, store.getSnapshot); | ||
} |
{ | ||
"name": "react-rx", | ||
"version": "3.0.0-2", | ||
"version": "3.0.0-3", | ||
"description": "React + RxJS = <3", | ||
@@ -77,4 +77,4 @@ "keywords": [ | ||
"@sanity/semantic-release-preset": "^2.0.5", | ||
"@testing-library/dom": "^8.20.1", | ||
"@testing-library/react": "^13.4.0", | ||
"@testing-library/dom": "^10.1.0", | ||
"@testing-library/react": "^16.0.0", | ||
"@types/jest": "^29.5.3", | ||
@@ -81,0 +81,0 @@ "@types/node": "^18.17.5", |
import {useEffect, useMemo, useRef, useSyncExternalStore} from 'react' | ||
import {Observable, Subscription} from 'rxjs' | ||
import type {Observable, Subscription} from 'rxjs' | ||
import {shareReplay, tap} from 'rxjs/operators' | ||
@@ -8,26 +8,10 @@ | ||
} | ||
interface CacheRecord<T> { | ||
subscription: Subscription | ||
observable: Observable<T> | ||
currentValue: T | ||
snapshot: T | ||
} | ||
const cache = new WeakMap<Observable<any>, CacheRecord<any>>() | ||
function getOrCreateStore<T>(inputObservable: Observable<T>, initialValue: T) { | ||
if (!cache.has(inputObservable)) { | ||
const entry: Partial<CacheRecord<T>> = {currentValue: initialValue} | ||
entry.observable = inputObservable.pipe( | ||
shareReplay({refCount: true, bufferSize: 1}), | ||
tap(value => (entry.currentValue = value)), | ||
) | ||
// Eagerly subscribe to sync set `entry.currentValue` to what the observable returns | ||
entry.subscription = entry.observable.subscribe() | ||
cache.set(inputObservable, entry as CacheRecord<T>) | ||
} | ||
return cache.get(inputObservable)! | ||
} | ||
export function useObservable<ObservableType extends Observable<any>>( | ||
@@ -41,3 +25,3 @@ observable: ObservableType, | ||
*/ | ||
const initialValueRef = useRef(getValue(initialValue)) | ||
const initialValueRef = useRef(getValue(initialValue) as UnboxObservable<ObservableType>) | ||
@@ -48,48 +32,39 @@ /** | ||
useEffect(() => { | ||
initialValueRef.current = getValue(initialValue) | ||
initialValueRef.current = getValue(initialValue) as UnboxObservable<ObservableType> | ||
}, [initialValue]) | ||
const [getSnapshot, subscribe] = useMemo< | ||
[() => UnboxObservable<ObservableType>, Parameters<typeof useSyncExternalStore>[0]] | ||
>(() => { | ||
const store = getOrCreateStore(observable, initialValueRef.current) | ||
if (store.subscription.closed) { | ||
store.subscription = store.observable.subscribe() | ||
} | ||
return [ | ||
function getSnapshot() { | ||
// @TODO: perf opt opportunity: we could do `store.subscription.unsubscribe()` here to clear up some memory, as this subscription is only needed to provide a sync initialValue. | ||
return store.currentValue | ||
}, | ||
function subscribe(callback: () => void) { | ||
// @TODO: perf opt opportunity: we could do `store.subscription.unsubscribe()` here as we only need 1 subscription active to keep the observer alive | ||
const sub = store.observable.subscribe(callback) | ||
return () => { | ||
sub.unsubscribe() | ||
} | ||
}, | ||
] | ||
}, [observable]) | ||
const store = useMemo(() => { | ||
if (!cache.has(observable)) { | ||
const entry: Partial<CacheRecord<UnboxObservable<ObservableType>>> = { | ||
snapshot: initialValueRef.current, | ||
} | ||
entry.observable = observable.pipe( | ||
shareReplay({refCount: true, bufferSize: 1}), | ||
tap(value => (entry.snapshot = value)), | ||
) | ||
const shouldRestoreSubscriptionRef = useRef(false) | ||
useEffect(() => { | ||
const store = getOrCreateStore(observable, initialValueRef.current) | ||
if (shouldRestoreSubscriptionRef.current) { | ||
if (store.subscription.closed) { | ||
store.subscription = store.observable.subscribe() | ||
} | ||
shouldRestoreSubscriptionRef.current = false | ||
// Eagerly subscribe to sync set `entry.currentValue` to what the observable returns, and keep the observable alive until the component unmounts. | ||
entry.subscription = entry.observable.subscribe() | ||
cache.set(observable, entry as CacheRecord<UnboxObservable<ObservableType>>) | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
const instance = cache.get(observable)! | ||
if (instance.subscription.closed) { | ||
instance.subscription = instance.observable.subscribe() | ||
} | ||
return () => { | ||
// React StrictMode will call effects as `setup + teardown + setup` thus we can't trust this callback as "react is about to unmount" | ||
// Tracking this ref lets us set the subscription back up on the next `setup` call if needed, and if it really did unmounted then all is well | ||
shouldRestoreSubscriptionRef.current = !store.subscription.closed | ||
store.subscription.unsubscribe() | ||
return { | ||
subscribe: (onStoreChange: () => void) => { | ||
const subscription = instance.observable.subscribe(onStoreChange) | ||
instance.subscription.unsubscribe() | ||
return () => subscription.unsubscribe() | ||
}, | ||
getSnapshot: () => instance.snapshot, | ||
} | ||
}, [observable]) | ||
return useSyncExternalStore<UnboxObservable<ObservableType>>(subscribe, getSnapshot) | ||
return useSyncExternalStore<UnboxObservable<ObservableType>>(store.subscribe, store.getSnapshot) | ||
} | ||
type UnboxObservable<T> = T extends Observable<infer U> ? U : never |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
56533
1083