react-rx 2.0.1 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/vcs.xml +0 -3
- package/dist/cjs/reactiveComponent.d.ts +1 -1
- package/dist/cjs/useAsObservable.js +20 -5
- package/dist/cjs/useObservable.js +28 -21
- package/dist/es2015/reactiveComponent.d.ts +1 -1
- package/dist/es2015/useAsObservable.js +20 -5
- package/dist/es2015/useObservable.js +28 -19
- package/dist/esm/reactiveComponent.d.ts +1 -1
- package/dist/esm/useAsObservable.js +21 -6
- package/dist/esm/useObservable.js +28 -21
- package/jest.config.ts +14 -0
- package/package.json +13 -13
- package/src/reactiveComponent.ts +3 -3
- package/src/useAsObservable.ts +23 -6
- package/src/useObservable.ts +44 -35
- package/tsconfig.json +1 -0
package/.idea/vcs.xml
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
2
|
<project version="4">
|
|
3
3
|
<component name="VcsDirectoryMappings">
|
|
4
|
-
<mapping directory="$PROJECT_DIR$/../../_/parcel-transformer-mdx-with-toc" vcs="Git" />
|
|
5
|
-
<mapping directory="$PROJECT_DIR$/../react-repl" vcs="Git" />
|
|
6
4
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
7
|
-
<mapping directory="$PROJECT_DIR$/../react-rx.dev" vcs="Git" />
|
|
8
5
|
</component>
|
|
9
6
|
</project>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import { FunctionComponent, ReactNode, Ref } from 'react';
|
|
3
3
|
declare type Component<Props> = (input$: Observable<Props>) => Observable<ReactNode>;
|
|
4
|
-
export declare function reactiveComponent<Props>(observable: Observable<Props>): FunctionComponent<
|
|
4
|
+
export declare function reactiveComponent<Props>(observable: Observable<Props>): FunctionComponent<Props>;
|
|
5
5
|
export declare function reactiveComponent<Props>(component: Component<Props>): FunctionComponent<Props>;
|
|
6
6
|
declare type ForwardRefComponent<RefType, Props> = (input$: Observable<Props>, ref: Ref<RefType>) => Observable<ReactNode>;
|
|
7
7
|
export declare function forwardRef<RefType, Props = {}>(component: ForwardRefComponent<RefType, Props>): import("react").ForwardRefExoticComponent<import("react").PropsWithoutRef<Props> & import("react").RefAttributes<RefType>>;
|
|
@@ -4,18 +4,33 @@ exports.useAsObservable = void 0;
|
|
|
4
4
|
var rxjs_1 = require("rxjs");
|
|
5
5
|
var react_1 = require("react");
|
|
6
6
|
var useIsomorphicEffect_1 = require("./useIsomorphicEffect");
|
|
7
|
+
var operators_1 = require("rxjs/operators");
|
|
7
8
|
function useAsObservable(value, operator) {
|
|
8
|
-
var
|
|
9
|
+
var setup = (0, react_1.useCallback)(function () {
|
|
9
10
|
var subject = new rxjs_1.BehaviorSubject(value);
|
|
10
|
-
var observable = subject.asObservable();
|
|
11
|
+
var observable = subject.asObservable().pipe((0, operators_1.distinctUntilChanged)());
|
|
11
12
|
return [operator ? observable.pipe(operator) : observable, subject];
|
|
12
|
-
}, [])
|
|
13
|
+
}, []);
|
|
14
|
+
var ref = (0, react_1.useRef)();
|
|
15
|
+
if (!ref.current) {
|
|
16
|
+
ref.current = setup();
|
|
17
|
+
}
|
|
18
|
+
var observable = ref.current[0];
|
|
13
19
|
(0, useIsomorphicEffect_1.useIsomorphicEffect)(function () {
|
|
20
|
+
if (!ref.current) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
var _a = ref.current, subject = _a[1];
|
|
14
24
|
subject.next(value);
|
|
15
|
-
}, [value]);
|
|
16
|
-
(0,
|
|
25
|
+
}, [value, ref]);
|
|
26
|
+
(0, useIsomorphicEffect_1.useIsomorphicEffect)(function () {
|
|
17
27
|
return function () {
|
|
28
|
+
if (!ref.current) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
var _a = ref.current, subject = _a[1];
|
|
18
32
|
subject.complete();
|
|
33
|
+
ref.current = undefined;
|
|
19
34
|
};
|
|
20
35
|
}, []);
|
|
21
36
|
return observable;
|
|
@@ -1,37 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useMemoObservable = exports.useObservable = void 0;
|
|
4
|
-
var rxjs_1 = require("rxjs");
|
|
5
4
|
var react_1 = require("react");
|
|
6
|
-
var useAsObservable_1 = require("./useAsObservable");
|
|
7
|
-
var operators_1 = require("rxjs/operators");
|
|
8
5
|
var shim_1 = require("use-sync-external-store/shim");
|
|
6
|
+
var operators_1 = require("rxjs/operators");
|
|
7
|
+
var useIsomorphicEffect_1 = require("./useIsomorphicEffect");
|
|
9
8
|
function getValue(value) {
|
|
10
9
|
return typeof value === 'function' ? value() : value;
|
|
11
10
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
var cache = new WeakMap();
|
|
12
|
+
function getOrCreateStore(inputObservable, initialValue) {
|
|
13
|
+
if (!cache.has(inputObservable)) {
|
|
14
|
+
var entry_1 = { currentValue: initialValue };
|
|
15
|
+
entry_1.observable = inputObservable.pipe((0, operators_1.shareReplay)({ refCount: true, bufferSize: 1 }), (0, operators_1.tap)(function (value) { return (entry_1.currentValue = value); }));
|
|
16
|
+
entry_1.subscription = entry_1.observable.subscribe();
|
|
17
|
+
cache.set(inputObservable, entry_1);
|
|
18
|
+
}
|
|
19
|
+
return cache.get(inputObservable);
|
|
20
|
+
}
|
|
21
|
+
function useObservable(observable, initialValue) {
|
|
22
|
+
var _a = (0, react_1.useMemo)(function () {
|
|
23
|
+
var record = getOrCreateStore(observable, getValue(initialValue));
|
|
24
|
+
return [
|
|
25
|
+
function getSnapshot() {
|
|
26
|
+
return record.currentValue;
|
|
27
|
+
},
|
|
28
|
+
function subscribe(callback) {
|
|
29
|
+
var sub = record.observable.subscribe(function (next) { return callback(next); });
|
|
23
30
|
return function () {
|
|
24
|
-
|
|
31
|
+
sub.unsubscribe();
|
|
25
32
|
};
|
|
26
33
|
},
|
|
34
|
+
];
|
|
35
|
+
}, [observable]), getSnapshot = _a[0], subscribe = _a[1];
|
|
36
|
+
(0, useIsomorphicEffect_1.useIsomorphicEffect)(function () {
|
|
37
|
+
return function () {
|
|
38
|
+
getOrCreateStore(observable, getValue(initialValue)).subscription.unsubscribe();
|
|
27
39
|
};
|
|
28
40
|
}, [observable]);
|
|
29
|
-
return (0, shim_1.useSyncExternalStore)(
|
|
30
|
-
}
|
|
31
|
-
function useObservable(observable, initialValue) {
|
|
32
|
-
return useObservableSubscription((0, useAsObservable_1.useAsObservable)(observable, (0, rxjs_1.pipe)((0, operators_1.distinctUntilChanged)(), (0, operators_1.switchMap)(function (observable) {
|
|
33
|
-
return (0, rxjs_1.merge)((0, rxjs_1.defer)(function () { return (0, rxjs_1.of)(getValue(initialValue)); }), observable);
|
|
34
|
-
}))));
|
|
41
|
+
return (0, shim_1.useSyncExternalStore)(subscribe, getSnapshot);
|
|
35
42
|
}
|
|
36
43
|
exports.useObservable = useObservable;
|
|
37
44
|
function useMemoObservable(observableOrFactory, deps, initialValue) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import { FunctionComponent, ReactNode, Ref } from 'react';
|
|
3
3
|
declare type Component<Props> = (input$: Observable<Props>) => Observable<ReactNode>;
|
|
4
|
-
export declare function reactiveComponent<Props>(observable: Observable<Props>): FunctionComponent<
|
|
4
|
+
export declare function reactiveComponent<Props>(observable: Observable<Props>): FunctionComponent<Props>;
|
|
5
5
|
export declare function reactiveComponent<Props>(component: Component<Props>): FunctionComponent<Props>;
|
|
6
6
|
declare type ForwardRefComponent<RefType, Props> = (input$: Observable<Props>, ref: Ref<RefType>) => Observable<ReactNode>;
|
|
7
7
|
export declare function forwardRef<RefType, Props = {}>(component: ForwardRefComponent<RefType, Props>): import("react").ForwardRefExoticComponent<import("react").PropsWithoutRef<Props> & import("react").RefAttributes<RefType>>;
|
|
@@ -1,18 +1,33 @@
|
|
|
1
1
|
import { BehaviorSubject } from 'rxjs';
|
|
2
|
-
import {
|
|
2
|
+
import { useCallback, useRef } from 'react';
|
|
3
3
|
import { useIsomorphicEffect } from './useIsomorphicEffect';
|
|
4
|
+
import { distinctUntilChanged } from 'rxjs/operators';
|
|
4
5
|
export function useAsObservable(value, operator) {
|
|
5
|
-
const
|
|
6
|
+
const setup = useCallback(() => {
|
|
6
7
|
const subject = new BehaviorSubject(value);
|
|
7
|
-
const observable = subject.asObservable();
|
|
8
|
+
const observable = subject.asObservable().pipe(distinctUntilChanged());
|
|
8
9
|
return [operator ? observable.pipe(operator) : observable, subject];
|
|
9
10
|
}, []);
|
|
11
|
+
const ref = useRef();
|
|
12
|
+
if (!ref.current) {
|
|
13
|
+
ref.current = setup();
|
|
14
|
+
}
|
|
15
|
+
const [observable] = ref.current;
|
|
10
16
|
useIsomorphicEffect(() => {
|
|
17
|
+
if (!ref.current) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const [, subject] = ref.current;
|
|
11
21
|
subject.next(value);
|
|
12
|
-
}, [value]);
|
|
13
|
-
|
|
22
|
+
}, [value, ref]);
|
|
23
|
+
useIsomorphicEffect(() => {
|
|
14
24
|
return () => {
|
|
25
|
+
if (!ref.current) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const [, subject] = ref.current;
|
|
15
29
|
subject.complete();
|
|
30
|
+
ref.current = undefined;
|
|
16
31
|
};
|
|
17
32
|
}, []);
|
|
18
33
|
return observable;
|
|
@@ -1,32 +1,41 @@
|
|
|
1
|
-
import { defer, merge, of, pipe } from 'rxjs';
|
|
2
1
|
import { useMemo } from 'react';
|
|
3
|
-
import { useAsObservable } from './useAsObservable';
|
|
4
|
-
import { distinctUntilChanged, switchMap } from 'rxjs/operators';
|
|
5
2
|
import { useSyncExternalStore } from 'use-sync-external-store/shim';
|
|
3
|
+
import { shareReplay, tap } from 'rxjs/operators';
|
|
4
|
+
import { useIsomorphicEffect } from './useIsomorphicEffect';
|
|
6
5
|
function getValue(value) {
|
|
7
6
|
return typeof value === 'function' ? value() : value;
|
|
8
7
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
8
|
+
const cache = new WeakMap();
|
|
9
|
+
function getOrCreateStore(inputObservable, initialValue) {
|
|
10
|
+
if (!cache.has(inputObservable)) {
|
|
11
|
+
const entry = { currentValue: initialValue };
|
|
12
|
+
entry.observable = inputObservable.pipe(shareReplay({ refCount: true, bufferSize: 1 }), tap(value => (entry.currentValue = value)));
|
|
13
|
+
entry.subscription = entry.observable.subscribe();
|
|
14
|
+
cache.set(inputObservable, entry);
|
|
15
|
+
}
|
|
16
|
+
return cache.get(inputObservable);
|
|
17
|
+
}
|
|
18
|
+
export function useObservable(observable, initialValue) {
|
|
19
|
+
const [getSnapshot, subscribe] = useMemo(() => {
|
|
20
|
+
const record = getOrCreateStore(observable, getValue(initialValue));
|
|
21
|
+
return [
|
|
22
|
+
function getSnapshot() {
|
|
23
|
+
return record.currentValue;
|
|
24
|
+
},
|
|
25
|
+
function subscribe(callback) {
|
|
26
|
+
const sub = record.observable.subscribe(next => callback(next));
|
|
20
27
|
return () => {
|
|
21
|
-
|
|
28
|
+
sub.unsubscribe();
|
|
22
29
|
};
|
|
23
30
|
},
|
|
31
|
+
];
|
|
32
|
+
}, [observable]);
|
|
33
|
+
useIsomorphicEffect(() => {
|
|
34
|
+
return () => {
|
|
35
|
+
getOrCreateStore(observable, getValue(initialValue)).subscription.unsubscribe();
|
|
24
36
|
};
|
|
25
37
|
}, [observable]);
|
|
26
|
-
return useSyncExternalStore(
|
|
27
|
-
}
|
|
28
|
-
export function useObservable(observable, initialValue) {
|
|
29
|
-
return useObservableSubscription(useAsObservable(observable, pipe(distinctUntilChanged(), switchMap(observable => merge(defer(() => of(getValue(initialValue))), observable)))));
|
|
38
|
+
return useSyncExternalStore(subscribe, getSnapshot);
|
|
30
39
|
}
|
|
31
40
|
export function useMemoObservable(observableOrFactory, deps, initialValue) {
|
|
32
41
|
return useObservable(useMemo(() => getValue(observableOrFactory), deps), initialValue);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import { FunctionComponent, ReactNode, Ref } from 'react';
|
|
3
3
|
declare type Component<Props> = (input$: Observable<Props>) => Observable<ReactNode>;
|
|
4
|
-
export declare function reactiveComponent<Props>(observable: Observable<Props>): FunctionComponent<
|
|
4
|
+
export declare function reactiveComponent<Props>(observable: Observable<Props>): FunctionComponent<Props>;
|
|
5
5
|
export declare function reactiveComponent<Props>(component: Component<Props>): FunctionComponent<Props>;
|
|
6
6
|
declare type ForwardRefComponent<RefType, Props> = (input$: Observable<Props>, ref: Ref<RefType>) => Observable<ReactNode>;
|
|
7
7
|
export declare function forwardRef<RefType, Props = {}>(component: ForwardRefComponent<RefType, Props>): import("react").ForwardRefExoticComponent<import("react").PropsWithoutRef<Props> & import("react").RefAttributes<RefType>>;
|
|
@@ -1,18 +1,33 @@
|
|
|
1
1
|
import { BehaviorSubject } from 'rxjs';
|
|
2
|
-
import {
|
|
2
|
+
import { useCallback, useRef } from 'react';
|
|
3
3
|
import { useIsomorphicEffect } from './useIsomorphicEffect';
|
|
4
|
+
import { distinctUntilChanged } from 'rxjs/operators';
|
|
4
5
|
export function useAsObservable(value, operator) {
|
|
5
|
-
var
|
|
6
|
+
var setup = useCallback(function () {
|
|
6
7
|
var subject = new BehaviorSubject(value);
|
|
7
|
-
var observable = subject.asObservable();
|
|
8
|
+
var observable = subject.asObservable().pipe(distinctUntilChanged());
|
|
8
9
|
return [operator ? observable.pipe(operator) : observable, subject];
|
|
9
|
-
}, [])
|
|
10
|
+
}, []);
|
|
11
|
+
var ref = useRef();
|
|
12
|
+
if (!ref.current) {
|
|
13
|
+
ref.current = setup();
|
|
14
|
+
}
|
|
15
|
+
var observable = ref.current[0];
|
|
10
16
|
useIsomorphicEffect(function () {
|
|
17
|
+
if (!ref.current) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
var _a = ref.current, subject = _a[1];
|
|
11
21
|
subject.next(value);
|
|
12
|
-
}, [value]);
|
|
13
|
-
|
|
22
|
+
}, [value, ref]);
|
|
23
|
+
useIsomorphicEffect(function () {
|
|
14
24
|
return function () {
|
|
25
|
+
if (!ref.current) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
var _a = ref.current, subject = _a[1];
|
|
15
29
|
subject.complete();
|
|
30
|
+
ref.current = undefined;
|
|
16
31
|
};
|
|
17
32
|
}, []);
|
|
18
33
|
return observable;
|
|
@@ -1,34 +1,41 @@
|
|
|
1
|
-
import { defer, merge, of, pipe } from 'rxjs';
|
|
2
1
|
import { useMemo } from 'react';
|
|
3
|
-
import { useAsObservable } from './useAsObservable';
|
|
4
|
-
import { distinctUntilChanged, switchMap } from 'rxjs/operators';
|
|
5
2
|
import { useSyncExternalStore } from 'use-sync-external-store/shim';
|
|
3
|
+
import { shareReplay, tap } from 'rxjs/operators';
|
|
4
|
+
import { useIsomorphicEffect } from './useIsomorphicEffect';
|
|
6
5
|
function getValue(value) {
|
|
7
6
|
return typeof value === 'function' ? value() : value;
|
|
8
7
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
8
|
+
var cache = new WeakMap();
|
|
9
|
+
function getOrCreateStore(inputObservable, initialValue) {
|
|
10
|
+
if (!cache.has(inputObservable)) {
|
|
11
|
+
var entry_1 = { currentValue: initialValue };
|
|
12
|
+
entry_1.observable = inputObservable.pipe(shareReplay({ refCount: true, bufferSize: 1 }), tap(function (value) { return (entry_1.currentValue = value); }));
|
|
13
|
+
entry_1.subscription = entry_1.observable.subscribe();
|
|
14
|
+
cache.set(inputObservable, entry_1);
|
|
15
|
+
}
|
|
16
|
+
return cache.get(inputObservable);
|
|
17
|
+
}
|
|
18
|
+
export function useObservable(observable, initialValue) {
|
|
19
|
+
var _a = useMemo(function () {
|
|
20
|
+
var record = getOrCreateStore(observable, getValue(initialValue));
|
|
21
|
+
return [
|
|
22
|
+
function getSnapshot() {
|
|
23
|
+
return record.currentValue;
|
|
24
|
+
},
|
|
25
|
+
function subscribe(callback) {
|
|
26
|
+
var sub = record.observable.subscribe(function (next) { return callback(next); });
|
|
20
27
|
return function () {
|
|
21
|
-
|
|
28
|
+
sub.unsubscribe();
|
|
22
29
|
};
|
|
23
30
|
},
|
|
31
|
+
];
|
|
32
|
+
}, [observable]), getSnapshot = _a[0], subscribe = _a[1];
|
|
33
|
+
useIsomorphicEffect(function () {
|
|
34
|
+
return function () {
|
|
35
|
+
getOrCreateStore(observable, getValue(initialValue)).subscription.unsubscribe();
|
|
24
36
|
};
|
|
25
37
|
}, [observable]);
|
|
26
|
-
return useSyncExternalStore(
|
|
27
|
-
}
|
|
28
|
-
export function useObservable(observable, initialValue) {
|
|
29
|
-
return useObservableSubscription(useAsObservable(observable, pipe(distinctUntilChanged(), switchMap(function (observable) {
|
|
30
|
-
return merge(defer(function () { return of(getValue(initialValue)); }), observable);
|
|
31
|
-
}))));
|
|
38
|
+
return useSyncExternalStore(subscribe, getSnapshot);
|
|
32
39
|
}
|
|
33
40
|
export function useMemoObservable(observableOrFactory, deps, initialValue) {
|
|
34
41
|
return useObservable(useMemo(function () { return getValue(observableOrFactory); }, deps), initialValue);
|
package/jest.config.ts
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-rx",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4",
|
|
4
4
|
"description": "React + RxJS = <3",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"types": "dist/cjs/index.d.ts",
|
|
@@ -30,12 +30,11 @@
|
|
|
30
30
|
"rxjs": "^6.5 || ^7"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@testing-library/dom": "^
|
|
34
|
-
"@testing-library/react": "^
|
|
35
|
-
"@
|
|
36
|
-
"@types/
|
|
37
|
-
"@types/react": "^
|
|
38
|
-
"@types/react-dom": "^17.0.1",
|
|
33
|
+
"@testing-library/dom": "^8.14.0",
|
|
34
|
+
"@testing-library/react": "^13.3.0",
|
|
35
|
+
"@types/jest": "^28.1.4",
|
|
36
|
+
"@types/react": "^18.0.12",
|
|
37
|
+
"@types/react-dom": "^18.0.5",
|
|
39
38
|
"@types/use-sync-external-store": "^0.0.3",
|
|
40
39
|
"@typescript-eslint/eslint-plugin": "^4.15.2",
|
|
41
40
|
"@typescript-eslint/parser": "^4.15.2",
|
|
@@ -43,16 +42,17 @@
|
|
|
43
42
|
"eslint-config-prettier": "^8.1.0",
|
|
44
43
|
"eslint-plugin-prettier": "^3.3.1",
|
|
45
44
|
"eslint-plugin-react": "^7.22.0",
|
|
46
|
-
"jest": "^
|
|
47
|
-
"jsdom": "^
|
|
45
|
+
"jest": "^28.1.2",
|
|
46
|
+
"jest-environment-jsdom": "^28.1.2",
|
|
47
|
+
"jsdom": "^20.0.0",
|
|
48
48
|
"npm-run-all": "^4.1.5",
|
|
49
49
|
"prettier": "2.2.1",
|
|
50
|
-
"react": "^
|
|
51
|
-
"react-dom": "^
|
|
52
|
-
"react-test-renderer": "^
|
|
50
|
+
"react": "^18.2.0",
|
|
51
|
+
"react-dom": "^18.2.0",
|
|
52
|
+
"react-test-renderer": "^18.2.0",
|
|
53
53
|
"rimraf": "^3.0.2",
|
|
54
54
|
"rxjs": "^6.5.5",
|
|
55
|
-
"ts-jest": "^
|
|
55
|
+
"ts-jest": "^28.0.5",
|
|
56
56
|
"typescript": "^4.2.2"
|
|
57
57
|
},
|
|
58
58
|
"repository": {
|
package/src/reactiveComponent.ts
CHANGED
|
@@ -26,16 +26,16 @@ function fromComponent<Props>(component: Component<Props>): FunctionComponent<Pr
|
|
|
26
26
|
return wrappedComponent
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
function fromObservable<Props>(input$: Observable<
|
|
29
|
+
function fromObservable<Props>(input$: Observable<ReactNode>): FunctionComponent<{}> {
|
|
30
30
|
return function ReactiveComponent() {
|
|
31
31
|
return createElement(Fragment, null, useObservable<ReactNode>(input$))
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export function reactiveComponent<Props>(observable: Observable<Props>): FunctionComponent<
|
|
35
|
+
export function reactiveComponent<Props>(observable: Observable<Props>): FunctionComponent<Props>
|
|
36
36
|
export function reactiveComponent<Props>(component: Component<Props>): FunctionComponent<Props>
|
|
37
37
|
export function reactiveComponent<Props>(
|
|
38
|
-
observableOrComponent: Observable<
|
|
38
|
+
observableOrComponent: Observable<ReactNode> | Component<Props>,
|
|
39
39
|
) {
|
|
40
40
|
return typeof observableOrComponent === 'function'
|
|
41
41
|
? fromComponent(observableOrComponent)
|
package/src/useAsObservable.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {BehaviorSubject, Observable} from 'rxjs'
|
|
2
|
-
import {
|
|
2
|
+
import {useCallback, useRef} from 'react'
|
|
3
3
|
import {useIsomorphicEffect} from './useIsomorphicEffect'
|
|
4
|
+
import {distinctUntilChanged} from 'rxjs/operators'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* React hook to convert any props or state value into an observable
|
|
@@ -17,22 +18,38 @@ export function useAsObservable<T, K = T>(
|
|
|
17
18
|
value: T,
|
|
18
19
|
operator?: (input: Observable<T>) => Observable<K>,
|
|
19
20
|
): Observable<T | K> {
|
|
20
|
-
const
|
|
21
|
+
const setup = useCallback((): [Observable<T | K>, BehaviorSubject<T>] => {
|
|
21
22
|
const subject = new BehaviorSubject(value)
|
|
22
23
|
|
|
23
|
-
const observable = subject.asObservable()
|
|
24
|
+
const observable = subject.asObservable().pipe(distinctUntilChanged())
|
|
24
25
|
return [operator ? observable.pipe(operator) : observable, subject]
|
|
25
26
|
}, [])
|
|
26
27
|
|
|
28
|
+
const ref = useRef<[Observable<T | K>, BehaviorSubject<T>]>()
|
|
29
|
+
|
|
30
|
+
if (!ref.current) {
|
|
31
|
+
ref.current = setup()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const [observable] = ref.current
|
|
35
|
+
|
|
27
36
|
useIsomorphicEffect(() => {
|
|
37
|
+
if (!ref.current) {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
const [, subject] = ref.current
|
|
28
41
|
subject.next(value)
|
|
29
|
-
}, [value])
|
|
42
|
+
}, [value, ref])
|
|
30
43
|
|
|
31
|
-
|
|
44
|
+
useIsomorphicEffect(() => {
|
|
32
45
|
return () => {
|
|
46
|
+
if (!ref.current) {
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
const [, subject] = ref.current
|
|
33
50
|
subject.complete()
|
|
51
|
+
ref.current = undefined
|
|
34
52
|
}
|
|
35
53
|
}, [])
|
|
36
|
-
|
|
37
54
|
return observable
|
|
38
55
|
}
|
package/src/useObservable.ts
CHANGED
|
@@ -1,51 +1,60 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {Observable, Subscription} from 'rxjs'
|
|
2
2
|
import {DependencyList, useMemo} from 'react'
|
|
3
|
-
import {useAsObservable} from './useAsObservable'
|
|
4
|
-
import {distinctUntilChanged, switchMap} from 'rxjs/operators'
|
|
5
3
|
import {useSyncExternalStore} from 'use-sync-external-store/shim'
|
|
4
|
+
import {shareReplay, tap} from 'rxjs/operators'
|
|
5
|
+
import {useIsomorphicEffect} from './useIsomorphicEffect'
|
|
6
6
|
|
|
7
7
|
function getValue<T>(value: T): T extends () => infer U ? U : T {
|
|
8
8
|
return typeof value === 'function' ? value() : value
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
11
|
+
interface CacheRecord<T> {
|
|
12
|
+
subscription: Subscription
|
|
13
|
+
observable: Observable<T>
|
|
14
|
+
currentValue: T
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const cache = new WeakMap<Observable<any>, CacheRecord<any>>()
|
|
18
|
+
function getOrCreateStore<T>(inputObservable: Observable<T>, initialValue: T) {
|
|
19
|
+
if (!cache.has(inputObservable)) {
|
|
20
|
+
const entry: Partial<CacheRecord<T>> = {currentValue: initialValue}
|
|
21
|
+
entry.observable = inputObservable.pipe(
|
|
22
|
+
shareReplay({refCount: true, bufferSize: 1}),
|
|
23
|
+
tap(value => (entry.currentValue = value)),
|
|
24
|
+
)
|
|
25
|
+
entry.subscription = entry.observable.subscribe()
|
|
26
|
+
|
|
27
|
+
cache.set(inputObservable, entry as CacheRecord<T>)
|
|
28
|
+
}
|
|
29
|
+
return cache.get(inputObservable)
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
export function useObservable<T>(observable: Observable<T>): T | undefined
|
|
32
33
|
export function useObservable<T>(observable: Observable<T>, initialValue: T): T
|
|
33
34
|
export function useObservable<T>(observable: Observable<T>, initialValue: () => T): T
|
|
34
35
|
export function useObservable<T>(observable: Observable<T>, initialValue?: T | (() => T)) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
)
|
|
36
|
+
const [getSnapshot, subscribe] = useMemo(() => {
|
|
37
|
+
const record = getOrCreateStore(observable, getValue(initialValue))!
|
|
38
|
+
return [
|
|
39
|
+
function getSnapshot() {
|
|
40
|
+
return record.currentValue
|
|
41
|
+
},
|
|
42
|
+
function subscribe(callback: (value: T) => void) {
|
|
43
|
+
const sub = record.observable.subscribe(next => callback(next))
|
|
44
|
+
return () => {
|
|
45
|
+
sub.unsubscribe()
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
]
|
|
49
|
+
}, [observable])
|
|
50
|
+
|
|
51
|
+
useIsomorphicEffect(() => {
|
|
52
|
+
return () => {
|
|
53
|
+
getOrCreateStore(observable, getValue(initialValue))!.subscription.unsubscribe()
|
|
54
|
+
}
|
|
55
|
+
}, [observable])
|
|
56
|
+
|
|
57
|
+
return useSyncExternalStore(subscribe, getSnapshot)
|
|
49
58
|
}
|
|
50
59
|
|
|
51
60
|
export function useMemoObservable<T>(
|