react-rx 2.1.2 → 3.0.0-0
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/dist/cjs/WithObservable.d.ts +1 -1
- package/dist/cjs/__tests__/strictmode.test.js +43 -18
- package/dist/cjs/__tests__/useAsObservable.test.js +12 -11
- package/dist/cjs/__tests__/useObservable.test.js +31 -30
- package/dist/cjs/reactiveComponent.d.ts +2 -2
- package/dist/cjs/useAsObservable.d.ts +1 -0
- package/dist/cjs/useObservable.js +16 -48
- package/dist/es2015/WithObservable.d.ts +1 -1
- package/dist/es2015/__tests__/strictmode.test.js +34 -9
- package/dist/es2015/__tests__/useAsObservable.test.js +1 -0
- package/dist/es2015/__tests__/useObservable.test.js +1 -0
- package/dist/es2015/reactiveComponent.d.ts +2 -2
- package/dist/es2015/useAsObservable.d.ts +1 -0
- package/dist/es2015/useObservable.js +18 -50
- package/dist/esm/WithObservable.d.ts +1 -1
- package/dist/esm/__tests__/strictmode.test.js +35 -10
- package/dist/esm/__tests__/useAsObservable.test.js +1 -0
- package/dist/esm/__tests__/useObservable.test.js +1 -0
- package/dist/esm/reactiveComponent.d.ts +2 -2
- package/dist/esm/useAsObservable.d.ts +1 -0
- package/dist/esm/useObservable.js +18 -50
- package/package.json +21 -27
- package/src/__tests__/strictmode.test.ts +37 -9
- package/src/__tests__/useAsObservable.test.tsx +1 -0
- package/src/__tests__/useObservable.test.tsx +1 -0
- package/src/useAsObservable.ts +1 -0
- package/src/useObservable.ts +20 -70
- package/src/utils.ts +1 -1
- package/dist/cjs/useIsomorphicEffect.d.ts +0 -2
- package/dist/cjs/useIsomorphicEffect.js +0 -5
- package/dist/cjs/withPropsStream.d.ts +0 -8
- package/dist/cjs/withPropsStream.js +0 -55
- package/dist/es2015/useIsomorphicEffect.d.ts +0 -2
- package/dist/es2015/useIsomorphicEffect.js +0 -2
- package/dist/es2015/withPropsStream.d.ts +0 -8
- package/dist/es2015/withPropsStream.js +0 -17
- package/dist/esm/useIsomorphicEffect.d.ts +0 -2
- package/dist/esm/useIsomorphicEffect.js +0 -2
- package/dist/esm/withPropsStream.d.ts +0 -8
- package/dist/esm/withPropsStream.js +0 -28
- package/src/useIsomorphicEffect.ts +0 -3
- package/src/withPropsStream.tsx +0 -27
|
@@ -4,7 +4,7 @@ interface Props<T> {
|
|
|
4
4
|
observable: Observable<T>;
|
|
5
5
|
children: (value: T) => ReactNode;
|
|
6
6
|
}
|
|
7
|
-
|
|
7
|
+
type ObservableComponent<T> = ComponentType<Props<T>>;
|
|
8
8
|
/**
|
|
9
9
|
* @deprecated Use the useObservable hook instead
|
|
10
10
|
*/
|
|
@@ -14,7 +14,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
14
14
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
15
|
function step(op) {
|
|
16
16
|
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
-
while (_) try {
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
18
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
19
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
20
|
switch (op[0]) {
|
|
@@ -41,14 +41,15 @@ var useObservable_1 = require("../useObservable");
|
|
|
41
41
|
var react_1 = require("react");
|
|
42
42
|
var react_2 = require("@testing-library/react");
|
|
43
43
|
var useAsObservable_1 = require("../useAsObservable");
|
|
44
|
+
var vitest_1 = require("vitest");
|
|
44
45
|
var wait = function (ms) { return new Promise(function (resolve) { return setTimeout(resolve, ms); }); };
|
|
45
46
|
// NOTE: Jest runs NODE_ENV=test by default, which enables development flags for React
|
|
46
|
-
test('Strict mode should trigger double mount effects and re-renders', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
47
|
+
(0, vitest_1.test)('Strict mode should trigger double mount effects and re-renders', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
47
48
|
function ObservableComponent() {
|
|
49
|
+
var observedValue = (0, useObservable_1.useObservable)(observable, 0);
|
|
48
50
|
(0, react_1.useEffect)(function () {
|
|
49
51
|
mountCount++;
|
|
50
52
|
}, []);
|
|
51
|
-
var observedValue = (0, useObservable_1.useObservable)(observable);
|
|
52
53
|
returnedValues.push(observedValue);
|
|
53
54
|
return (0, react_1.createElement)(react_1.Fragment, null, observedValue);
|
|
54
55
|
}
|
|
@@ -61,26 +62,29 @@ test('Strict mode should trigger double mount effects and re-renders', function
|
|
|
61
62
|
returnedValues = [];
|
|
62
63
|
mountCount = 0;
|
|
63
64
|
rerender = (0, react_2.render)((0, react_1.createElement)(react_1.StrictMode, null, (0, react_1.createElement)(ObservableComponent))).rerender;
|
|
64
|
-
expect(mountCount).
|
|
65
|
-
expect(returnedValues).toEqual([0, 0]);
|
|
65
|
+
(0, vitest_1.expect)(mountCount).toBe(2);
|
|
66
|
+
(0, vitest_1.expect)(returnedValues).toEqual([0, 0]);
|
|
66
67
|
return [4 /*yield*/, wait(10)];
|
|
67
68
|
case 1:
|
|
68
69
|
_a.sent();
|
|
69
70
|
(0, react_2.act)(function () { return subject.next(1); });
|
|
70
|
-
expect(returnedValues).toEqual([0, 0, 1, 1]);
|
|
71
|
+
(0, vitest_1.expect)(returnedValues).toEqual([0, 0, 1, 1]);
|
|
71
72
|
(0, react_2.act)(function () { return subject.next(2); });
|
|
72
|
-
expect(returnedValues).toEqual([0, 0, 1, 1, 2, 2]);
|
|
73
|
-
expect(mountCount).toEqual(2);
|
|
73
|
+
(0, vitest_1.expect)(returnedValues).toEqual([0, 0, 1, 1, 2, 2]);
|
|
74
|
+
(0, vitest_1.expect)(mountCount).toEqual(2);
|
|
74
75
|
return [2 /*return*/];
|
|
75
76
|
}
|
|
76
77
|
});
|
|
77
78
|
}); });
|
|
78
|
-
test('Strict mode should unsubscribe the source observable on unmount', function () {
|
|
79
|
-
var subscribed =
|
|
79
|
+
(0, vitest_1.test)('Strict mode should unsubscribe the source observable on unmount', function () {
|
|
80
|
+
var subscribed = [];
|
|
81
|
+
var unsubscribed = [];
|
|
82
|
+
var nextId = 0;
|
|
80
83
|
var observable = new rxjs_1.Observable(function () {
|
|
81
|
-
|
|
84
|
+
var id = nextId++;
|
|
85
|
+
subscribed.push(id);
|
|
82
86
|
return function () {
|
|
83
|
-
|
|
87
|
+
unsubscribed.push(id);
|
|
84
88
|
};
|
|
85
89
|
});
|
|
86
90
|
function ObservableComponent() {
|
|
@@ -88,14 +92,35 @@ test('Strict mode should unsubscribe the source observable on unmount', function
|
|
|
88
92
|
return (0, react_1.createElement)(react_1.Fragment, null);
|
|
89
93
|
}
|
|
90
94
|
var rerender = (0, react_2.render)((0, react_1.createElement)(react_1.StrictMode, null, (0, react_1.createElement)(ObservableComponent))).rerender;
|
|
91
|
-
expect(subscribed).
|
|
95
|
+
(0, vitest_1.expect)(subscribed).toEqual([0, 1]);
|
|
92
96
|
rerender((0, react_1.createElement)(react_1.StrictMode, null, (0, react_1.createElement)('div')));
|
|
93
|
-
expect(
|
|
97
|
+
(0, vitest_1.expect)(unsubscribed).toEqual([0, 1]);
|
|
94
98
|
});
|
|
95
|
-
test('
|
|
99
|
+
(0, vitest_1.test)('useMemoObservable should unsubscribe the source observable on unmount', function () {
|
|
100
|
+
var subscribed = [];
|
|
101
|
+
var unsubscribed = [];
|
|
102
|
+
var nextId = 0;
|
|
103
|
+
function ObservableComponent() {
|
|
104
|
+
(0, useObservable_1.useMemoObservable)(function () {
|
|
105
|
+
return new rxjs_1.Observable(function () {
|
|
106
|
+
var id = nextId++;
|
|
107
|
+
subscribed.push(id);
|
|
108
|
+
return function () {
|
|
109
|
+
unsubscribed.push(id);
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
}, []);
|
|
113
|
+
return (0, react_1.createElement)(react_1.Fragment, null);
|
|
114
|
+
}
|
|
115
|
+
var rerender = (0, react_2.render)((0, react_1.createElement)(react_1.StrictMode, null, (0, react_1.createElement)(ObservableComponent))).rerender;
|
|
116
|
+
(0, vitest_1.expect)(subscribed).toEqual([0, 1]);
|
|
117
|
+
rerender((0, react_1.createElement)(react_1.StrictMode, null, (0, react_1.createElement)('div')));
|
|
118
|
+
(0, vitest_1.expect)(unsubscribed).toEqual([0, 1]);
|
|
119
|
+
});
|
|
120
|
+
(0, vitest_1.test)('useAsObservable should work in strict mode', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
96
121
|
function ObservableComponent(props) {
|
|
97
122
|
var count$ = (0, useAsObservable_1.useAsObservable)(props.count);
|
|
98
|
-
var count = (0, useObservable_1.useObservable)(count
|
|
123
|
+
var count = (0, useObservable_1.useObservable)(count$, props.count);
|
|
99
124
|
returnedValues.push(count);
|
|
100
125
|
return (0, react_1.createElement)(react_1.Fragment, null, 'ok');
|
|
101
126
|
}
|
|
@@ -103,9 +128,9 @@ test('useAsObservable should work in strict mode', function () { return __awaite
|
|
|
103
128
|
return __generator(this, function (_a) {
|
|
104
129
|
returnedValues = [];
|
|
105
130
|
rerender = (0, react_2.render)((0, react_1.createElement)(react_1.StrictMode, null, (0, react_1.createElement)(ObservableComponent, { count: 0 }))).rerender;
|
|
106
|
-
expect(returnedValues).toEqual([0, 0]);
|
|
131
|
+
(0, vitest_1.expect)(returnedValues).toEqual([0, 0]);
|
|
107
132
|
rerender((0, react_1.createElement)(react_1.StrictMode, null, (0, react_1.createElement)(ObservableComponent, { count: 1 })));
|
|
108
|
-
expect(returnedValues).toEqual([0, 0, 0, 0, 1, 1]);
|
|
133
|
+
(0, vitest_1.expect)(returnedValues).toEqual([0, 0, 0, 0, 1, 1]);
|
|
109
134
|
return [2 /*return*/];
|
|
110
135
|
});
|
|
111
136
|
}); });
|
|
@@ -6,7 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
var useAsObservable_1 = require("../useAsObservable");
|
|
7
7
|
var react_1 = __importDefault(require("react"));
|
|
8
8
|
var react_2 = require("@testing-library/react");
|
|
9
|
-
|
|
9
|
+
var vitest_1 = require("vitest");
|
|
10
|
+
(0, vitest_1.test)('the returned observable should receive a new value when component is rendered with a new value', function () {
|
|
10
11
|
var receivedValues = [];
|
|
11
12
|
var _a = (0, react_2.renderHook)(function (props) {
|
|
12
13
|
var observable = (0, useAsObservable_1.useAsObservable)(props.value);
|
|
@@ -21,10 +22,10 @@ test('the returned observable should receive a new value when component is rende
|
|
|
21
22
|
}, { initialProps: { value: 'initial' } }), unmount = _a.unmount, rerender = _a.rerender;
|
|
22
23
|
rerender({ value: 'rerender' });
|
|
23
24
|
rerender({ value: 'rerender again' });
|
|
24
|
-
expect(receivedValues).toEqual(['initial', 'rerender', 'rerender again']);
|
|
25
|
+
(0, vitest_1.expect)(receivedValues).toEqual(['initial', 'rerender', 'rerender again']);
|
|
25
26
|
unmount();
|
|
26
27
|
});
|
|
27
|
-
test('the returned observable should *not* receive a new value when component is rendered with an unchanged value', function () {
|
|
28
|
+
(0, vitest_1.test)('the returned observable should *not* receive a new value when component is rendered with an unchanged value', function () {
|
|
28
29
|
var receivedValues = [];
|
|
29
30
|
var _a = (0, react_2.renderHook)(function (props) {
|
|
30
31
|
var observable = (0, useAsObservable_1.useAsObservable)(props.value);
|
|
@@ -39,10 +40,10 @@ test('the returned observable should *not* receive a new value when component is
|
|
|
39
40
|
}, { initialProps: { value: 'some value' } }), unmount = _a.unmount, rerender = _a.rerender;
|
|
40
41
|
rerender({ value: 'some value' });
|
|
41
42
|
rerender({ value: 'some value' });
|
|
42
|
-
expect(receivedValues).toEqual(['some value']);
|
|
43
|
+
(0, vitest_1.expect)(receivedValues).toEqual(['some value']);
|
|
43
44
|
unmount();
|
|
44
45
|
});
|
|
45
|
-
test('the returned observable should have the same identity across multiple re-renders/hook calls', function () {
|
|
46
|
+
(0, vitest_1.test)('the returned observable should have the same identity across multiple re-renders/hook calls', function () {
|
|
46
47
|
var returnValues = [];
|
|
47
48
|
var _a = (0, react_2.renderHook)(function () {
|
|
48
49
|
returnValues.push((0, useAsObservable_1.useAsObservable)('render'));
|
|
@@ -50,11 +51,11 @@ test('the returned observable should have the same identity across multiple re-r
|
|
|
50
51
|
rerender();
|
|
51
52
|
rerender();
|
|
52
53
|
var initial = returnValues[0], firstRerender = returnValues[1], secondRerender = returnValues[2];
|
|
53
|
-
expect(initial).toBe(firstRerender);
|
|
54
|
-
expect(firstRerender).toBe(secondRerender);
|
|
54
|
+
(0, vitest_1.expect)(initial).toBe(firstRerender);
|
|
55
|
+
(0, vitest_1.expect)(firstRerender).toBe(secondRerender);
|
|
55
56
|
unmount();
|
|
56
57
|
});
|
|
57
|
-
test('the returned observable should complete on unmount', function () {
|
|
58
|
+
(0, vitest_1.test)('the returned observable should complete on unmount', function () {
|
|
58
59
|
var didComplete = false;
|
|
59
60
|
var _a = (0, react_2.renderHook)(function () {
|
|
60
61
|
var observable = (0, useAsObservable_1.useAsObservable)('render');
|
|
@@ -69,9 +70,9 @@ test('the returned observable should complete on unmount', function () {
|
|
|
69
70
|
};
|
|
70
71
|
}, []);
|
|
71
72
|
}), unmount = _a.unmount, rerender = _a.rerender;
|
|
72
|
-
expect(didComplete).toBe(false);
|
|
73
|
+
(0, vitest_1.expect)(didComplete).toBe(false);
|
|
73
74
|
rerender();
|
|
74
|
-
expect(didComplete).toBe(false);
|
|
75
|
+
(0, vitest_1.expect)(didComplete).toBe(false);
|
|
75
76
|
unmount();
|
|
76
|
-
expect(didComplete).toBe(true);
|
|
77
|
+
(0, vitest_1.expect)(didComplete).toBe(true);
|
|
77
78
|
});
|
|
@@ -5,7 +5,8 @@ var useObservable_1 = require("../useObservable");
|
|
|
5
5
|
var rxjs_1 = require("rxjs");
|
|
6
6
|
var operators_1 = require("rxjs/operators");
|
|
7
7
|
var react_2 = require("react");
|
|
8
|
-
|
|
8
|
+
var vitest_1 = require("vitest");
|
|
9
|
+
(0, vitest_1.test)('should subscribe immediately on component mount and unsubscribe on component unmount', function () {
|
|
9
10
|
var subscribed = false;
|
|
10
11
|
var observable = new rxjs_1.Observable(function () {
|
|
11
12
|
subscribed = true;
|
|
@@ -13,27 +14,27 @@ test('should subscribe immediately on component mount and unsubscribe on compone
|
|
|
13
14
|
subscribed = false;
|
|
14
15
|
};
|
|
15
16
|
});
|
|
16
|
-
expect(subscribed).toBe(false);
|
|
17
|
+
(0, vitest_1.expect)(subscribed).toBe(false);
|
|
17
18
|
var unmount = (0, react_1.renderHook)(function () { return (0, useObservable_1.useObservable)(observable); }).unmount;
|
|
18
|
-
expect(subscribed).toBe(true);
|
|
19
|
+
(0, vitest_1.expect)(subscribed).toBe(true);
|
|
19
20
|
unmount();
|
|
20
|
-
expect(subscribed).toBe(false);
|
|
21
|
+
(0, vitest_1.expect)(subscribed).toBe(false);
|
|
21
22
|
});
|
|
22
|
-
test('should only subscribe once when given same observable on re-renders', function () {
|
|
23
|
+
(0, vitest_1.test)('should only subscribe once when given same observable on re-renders', function () {
|
|
23
24
|
var subscriptionCount = 0;
|
|
24
25
|
var observable = new rxjs_1.Observable(function () {
|
|
25
26
|
subscriptionCount++;
|
|
26
27
|
});
|
|
27
|
-
expect(subscriptionCount).toBe(0);
|
|
28
|
+
(0, vitest_1.expect)(subscriptionCount).toBe(0);
|
|
28
29
|
var _a = (0, react_1.renderHook)(function () { return (0, useObservable_1.useObservable)(observable); }), unmount = _a.unmount, rerender = _a.rerender;
|
|
29
|
-
expect(subscriptionCount).toBe(1);
|
|
30
|
+
(0, vitest_1.expect)(subscriptionCount).toBe(1);
|
|
30
31
|
rerender();
|
|
31
|
-
expect(subscriptionCount).toBe(1);
|
|
32
|
+
(0, vitest_1.expect)(subscriptionCount).toBe(1);
|
|
32
33
|
unmount();
|
|
33
34
|
(0, react_1.renderHook)(function () { return (0, useObservable_1.useObservable)(observable); });
|
|
34
|
-
expect(subscriptionCount).toBe(2);
|
|
35
|
+
(0, vitest_1.expect)(subscriptionCount).toBe(2);
|
|
35
36
|
});
|
|
36
|
-
test('should not return undefined during render if initial value is given', function () {
|
|
37
|
+
(0, vitest_1.test)('should not return undefined during render if initial value is given', function () {
|
|
37
38
|
var observable = (0, rxjs_1.timer)(100).pipe((0, operators_1.mapTo)('emitted value'));
|
|
38
39
|
var returnedValues = [];
|
|
39
40
|
function ObservableComponent() {
|
|
@@ -42,9 +43,9 @@ test('should not return undefined during render if initial value is given', func
|
|
|
42
43
|
return (0, react_2.createElement)(react_2.Fragment, null, observedValue);
|
|
43
44
|
}
|
|
44
45
|
(0, react_1.render)((0, react_2.createElement)(ObservableComponent));
|
|
45
|
-
expect(returnedValues).toEqual(expect.arrayContaining(['initial value']));
|
|
46
|
+
(0, vitest_1.expect)(returnedValues).toEqual(vitest_1.expect.arrayContaining(['initial value']));
|
|
46
47
|
});
|
|
47
|
-
test('should not return undefined during render if observable is sync', function () {
|
|
48
|
+
(0, vitest_1.test)('should not return undefined during render if observable is sync', function () {
|
|
48
49
|
var observable = (0, rxjs_1.of)('initial value');
|
|
49
50
|
var returnedValues = [];
|
|
50
51
|
function ObservableComponent() {
|
|
@@ -53,9 +54,9 @@ test('should not return undefined during render if observable is sync', function
|
|
|
53
54
|
return (0, react_2.createElement)(react_2.Fragment, null, observedValue);
|
|
54
55
|
}
|
|
55
56
|
(0, react_1.render)((0, react_2.createElement)(ObservableComponent));
|
|
56
|
-
expect(returnedValues).toEqual(expect.arrayContaining(['initial value']));
|
|
57
|
+
(0, vitest_1.expect)(returnedValues).toEqual(vitest_1.expect.arrayContaining(['initial value']));
|
|
57
58
|
});
|
|
58
|
-
test('should return undefined during first render if observable is async', function () {
|
|
59
|
+
(0, vitest_1.test)('should return undefined during first render if observable is async', function () {
|
|
59
60
|
var observable = (0, rxjs_1.scheduled)('async value', rxjs_1.asyncScheduler);
|
|
60
61
|
var returnedValues = [];
|
|
61
62
|
function ObservableComponent() {
|
|
@@ -64,53 +65,53 @@ test('should return undefined during first render if observable is async', funct
|
|
|
64
65
|
return (0, react_2.createElement)(react_2.Fragment, null, observedValue);
|
|
65
66
|
}
|
|
66
67
|
(0, react_1.render)((0, react_2.createElement)(ObservableComponent));
|
|
67
|
-
expect(returnedValues).toEqual(expect.arrayContaining([undefined]));
|
|
68
|
+
(0, vitest_1.expect)(returnedValues).toEqual(vitest_1.expect.arrayContaining([undefined]));
|
|
68
69
|
});
|
|
69
|
-
test('should have sync values from an observable as initial value', function () {
|
|
70
|
+
(0, vitest_1.test)('should have sync values from an observable as initial value', function () {
|
|
70
71
|
var observable = (0, rxjs_1.of)('something sync');
|
|
71
72
|
var result = (0, react_1.renderHook)(function () { return (0, useObservable_1.useObservable)(observable); }).result;
|
|
72
|
-
expect(result.current).toBe('something sync');
|
|
73
|
+
(0, vitest_1.expect)(result.current).toBe('something sync');
|
|
73
74
|
});
|
|
74
|
-
test('should have undefined as initial value from delayed observables', function () {
|
|
75
|
+
(0, vitest_1.test)('should have undefined as initial value from delayed observables', function () {
|
|
75
76
|
var _a = (0, react_1.renderHook)(function () {
|
|
76
77
|
return (0, useObservable_1.useObservable)((0, rxjs_1.scheduled)('something async', rxjs_1.asyncScheduler));
|
|
77
78
|
}), result = _a.result, unmount = _a.unmount;
|
|
78
|
-
expect(result.current).toBeUndefined();
|
|
79
|
+
(0, vitest_1.expect)(result.current).toBeUndefined();
|
|
79
80
|
unmount();
|
|
80
81
|
});
|
|
81
|
-
test('should have passed initialValue as initial value from delayed observables', function () {
|
|
82
|
+
(0, vitest_1.test)('should have passed initialValue as initial value from delayed observables', function () {
|
|
82
83
|
var _a = (0, react_1.renderHook)(function () {
|
|
83
84
|
return (0, useObservable_1.useObservable)((0, rxjs_1.scheduled)('something async', rxjs_1.asyncScheduler), 'initial');
|
|
84
85
|
}), result = _a.result, unmount = _a.unmount;
|
|
85
|
-
expect(result.current).toBe('initial');
|
|
86
|
+
(0, vitest_1.expect)(result.current).toBe('initial');
|
|
86
87
|
unmount();
|
|
87
88
|
});
|
|
88
|
-
test('should update with values from observables', function () {
|
|
89
|
+
(0, vitest_1.test)('should update with values from observables', function () {
|
|
89
90
|
var values$ = new rxjs_1.Subject();
|
|
90
91
|
var _a = (0, react_1.renderHook)(function () { return (0, useObservable_1.useObservable)(values$); }), result = _a.result, unmount = _a.unmount;
|
|
91
|
-
expect(result.current).toBe(undefined);
|
|
92
|
+
(0, vitest_1.expect)(result.current).toBe(undefined);
|
|
92
93
|
(0, react_1.act)(function () { return values$.next('something'); });
|
|
93
|
-
expect(result.current).toBe('something');
|
|
94
|
+
(0, vitest_1.expect)(result.current).toBe('something');
|
|
94
95
|
(0, react_1.act)(function () { return values$.next('otherthing'); });
|
|
95
|
-
expect(result.current).toBe('otherthing');
|
|
96
|
+
(0, vitest_1.expect)(result.current).toBe('otherthing');
|
|
96
97
|
unmount();
|
|
97
98
|
});
|
|
98
|
-
test('should re-subscribe when receiving a new observable', function () {
|
|
99
|
+
(0, vitest_1.test)('should re-subscribe when receiving a new observable', function () {
|
|
99
100
|
var first$ = new rxjs_1.Subject();
|
|
100
101
|
var second$ = new rxjs_1.Subject();
|
|
101
102
|
var current$ = first$;
|
|
102
103
|
var _a = (0, react_1.renderHook)(function () { return (0, useObservable_1.useObservable)(current$, '!!initial!!'); }), result = _a.result, rerender = _a.rerender, unmount = _a.unmount;
|
|
103
104
|
(0, react_1.act)(function () { return first$.next('first 1'); });
|
|
104
|
-
expect(result.current).toBe('first 1');
|
|
105
|
+
(0, vitest_1.expect)(result.current).toBe('first 1');
|
|
105
106
|
current$ = second$;
|
|
106
107
|
rerender();
|
|
107
108
|
// since observable #2 hasn't emitted a value yet, we should use the initial value
|
|
108
|
-
expect(result.current).toBe('!!initial!!');
|
|
109
|
+
(0, vitest_1.expect)(result.current).toBe('!!initial!!');
|
|
109
110
|
// Now we should be subscribed to second$ and it's emission should be returned
|
|
110
111
|
(0, react_1.act)(function () { return second$.next('second 1'); });
|
|
111
|
-
expect(result.current).toBe('second 1');
|
|
112
|
+
(0, vitest_1.expect)(result.current).toBe('second 1');
|
|
112
113
|
// we should no longer be subscribed to the first and ignore any emissions
|
|
113
114
|
(0, react_1.act)(function () { return first$.next('first 2'); });
|
|
114
|
-
expect(result.current).toBe('second 1');
|
|
115
|
+
(0, vitest_1.expect)(result.current).toBe('second 1');
|
|
115
116
|
unmount();
|
|
116
117
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import { FunctionComponent, ReactNode, Ref } from 'react';
|
|
3
|
-
|
|
3
|
+
type Component<Props> = (input$: Observable<Props>) => Observable<ReactNode>;
|
|
4
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
|
+
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>>;
|
|
8
8
|
export {};
|
|
@@ -4,6 +4,7 @@ import { Observable } from 'rxjs';
|
|
|
4
4
|
* Returns an observable representing updates to any React value (props, state or any other calculated value)
|
|
5
5
|
* Note: the returned observable is the same instance throughout the component lifecycle
|
|
6
6
|
* @param value
|
|
7
|
+
* @deprecated use an `of` operator and `useMemoObservable` instead for a faster, more robust and siimpler solution
|
|
7
8
|
*/
|
|
8
9
|
export declare function useAsObservable<T>(value: T): Observable<T>;
|
|
9
10
|
export declare function useAsObservable<T, K>(value: T, operator: (input: Observable<T>) => Observable<K>): Observable<K>;
|
|
@@ -2,62 +2,30 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useMemoObservable = exports.useObservable = void 0;
|
|
4
4
|
var react_1 = require("react");
|
|
5
|
-
var shim_1 = require("use-sync-external-store/shim");
|
|
6
5
|
var operators_1 = require("rxjs/operators");
|
|
7
6
|
function getValue(value) {
|
|
8
7
|
return typeof value === 'function' ? value() : value;
|
|
9
8
|
}
|
|
10
|
-
var cache = new WeakMap();
|
|
11
|
-
function getOrCreateStore(inputObservable, initialValue) {
|
|
12
|
-
if (!cache.has(inputObservable)) {
|
|
13
|
-
var entry_1 = { currentValue: initialValue };
|
|
14
|
-
entry_1.observable = inputObservable.pipe((0, operators_1.shareReplay)({ refCount: true, bufferSize: 1 }), (0, operators_1.tap)(function (value) { return (entry_1.currentValue = value); }));
|
|
15
|
-
// Eagerly subscribe to sync set `entry.currentValue` to what the observable returns
|
|
16
|
-
entry_1.subscription = entry_1.observable.subscribe();
|
|
17
|
-
cache.set(inputObservable, entry_1);
|
|
18
|
-
}
|
|
19
|
-
return cache.get(inputObservable);
|
|
20
|
-
}
|
|
21
9
|
function useObservable(observable, initialValue) {
|
|
22
|
-
var _a = (0, react_1.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
store.subscription = store.observable.subscribe();
|
|
26
|
-
}
|
|
27
|
-
return [
|
|
28
|
-
function getSnapshot() {
|
|
29
|
-
// @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.
|
|
30
|
-
return store.currentValue;
|
|
31
|
-
},
|
|
32
|
-
function subscribe(callback) {
|
|
33
|
-
// @TODO: perf opt opportunity: we could do `store.subscription.unsubscribe()` here as we only need 1 subscription active to keep the observer alive
|
|
34
|
-
var sub = store.observable.subscribe(callback);
|
|
35
|
-
return function () {
|
|
36
|
-
sub.unsubscribe();
|
|
37
|
-
};
|
|
38
|
-
},
|
|
39
|
-
];
|
|
40
|
-
}, [observable]), getSnapshot = _a[0], subscribe = _a[1];
|
|
41
|
-
var shouldRestoreSubscriptionRef = (0, react_1.useRef)(false);
|
|
10
|
+
var _a = (0, react_1.useState)(function () { return getValue(initialValue); }), value = _a[0], setValue = _a[1];
|
|
11
|
+
var initialValueRef = (0, react_1.useRef)(initialValue);
|
|
12
|
+
initialValueRef.current = initialValue;
|
|
42
13
|
(0, react_1.useEffect)(function () {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
shouldRestoreSubscriptionRef.current = false;
|
|
49
|
-
}
|
|
50
|
-
return function () {
|
|
51
|
-
// React StrictMode will call effects as `setup + teardown + setup` thus we can't trust this callback as "react is about to unmount"
|
|
52
|
-
// 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
|
|
53
|
-
shouldRestoreSubscriptionRef.current = !store.subscription.closed;
|
|
54
|
-
store.subscription.unsubscribe();
|
|
55
|
-
};
|
|
56
|
-
}, [observable]);
|
|
57
|
-
return (0, shim_1.useSyncExternalStore)(subscribe, getSnapshot);
|
|
14
|
+
setValue(getValue(initialValueRef.current));
|
|
15
|
+
var subscription = observable.pipe((0, operators_1.tap)(function (next) { return setValue(next); })).subscribe();
|
|
16
|
+
return function () { return subscription.unsubscribe(); };
|
|
17
|
+
}, [initialValueRef, observable]);
|
|
18
|
+
return value;
|
|
58
19
|
}
|
|
59
20
|
exports.useObservable = useObservable;
|
|
60
21
|
function useMemoObservable(observableOrFactory, deps, initialValue) {
|
|
61
|
-
|
|
22
|
+
var _a = (0, react_1.useState)(function () { return getValue(initialValue); }), value = _a[0], setValue = _a[1];
|
|
23
|
+
(0, react_1.useEffect)(function () {
|
|
24
|
+
var subscription = getValue(observableOrFactory)
|
|
25
|
+
.pipe((0, operators_1.tap)(function (next) { return setValue(next); }))
|
|
26
|
+
.subscribe();
|
|
27
|
+
return function () { return subscription.unsubscribe(); };
|
|
28
|
+
}, deps);
|
|
29
|
+
return value;
|
|
62
30
|
}
|
|
63
31
|
exports.useMemoObservable = useMemoObservable;
|
|
@@ -4,7 +4,7 @@ interface Props<T> {
|
|
|
4
4
|
observable: Observable<T>;
|
|
5
5
|
children: (value: T) => ReactNode;
|
|
6
6
|
}
|
|
7
|
-
|
|
7
|
+
type ObservableComponent<T> = ComponentType<Props<T>>;
|
|
8
8
|
/**
|
|
9
9
|
* @deprecated Use the useObservable hook instead
|
|
10
10
|
*/
|
|
@@ -8,10 +8,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { BehaviorSubject, Observable } from 'rxjs';
|
|
11
|
-
import { useObservable } from '../useObservable';
|
|
11
|
+
import { useMemoObservable, useObservable } from '../useObservable';
|
|
12
12
|
import { createElement, Fragment, StrictMode, useEffect } from 'react';
|
|
13
13
|
import { act, render } from '@testing-library/react';
|
|
14
14
|
import { useAsObservable } from '../useAsObservable';
|
|
15
|
+
import { test, expect } from 'vitest';
|
|
15
16
|
const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
16
17
|
// NOTE: Jest runs NODE_ENV=test by default, which enables development flags for React
|
|
17
18
|
test('Strict mode should trigger double mount effects and re-renders', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -20,15 +21,15 @@ test('Strict mode should trigger double mount effects and re-renders', () => __a
|
|
|
20
21
|
const returnedValues = [];
|
|
21
22
|
let mountCount = 0;
|
|
22
23
|
function ObservableComponent() {
|
|
24
|
+
const observedValue = useObservable(observable, 0);
|
|
23
25
|
useEffect(() => {
|
|
24
26
|
mountCount++;
|
|
25
27
|
}, []);
|
|
26
|
-
const observedValue = useObservable(observable);
|
|
27
28
|
returnedValues.push(observedValue);
|
|
28
29
|
return createElement(Fragment, null, observedValue);
|
|
29
30
|
}
|
|
30
31
|
const { rerender } = render(createElement(StrictMode, null, createElement(ObservableComponent)));
|
|
31
|
-
expect(mountCount).
|
|
32
|
+
expect(mountCount).toBe(2);
|
|
32
33
|
expect(returnedValues).toEqual([0, 0]);
|
|
33
34
|
yield wait(10);
|
|
34
35
|
act(() => subject.next(1));
|
|
@@ -38,11 +39,14 @@ test('Strict mode should trigger double mount effects and re-renders', () => __a
|
|
|
38
39
|
expect(mountCount).toEqual(2);
|
|
39
40
|
}));
|
|
40
41
|
test('Strict mode should unsubscribe the source observable on unmount', () => {
|
|
41
|
-
|
|
42
|
+
const subscribed = [];
|
|
43
|
+
const unsubscribed = [];
|
|
44
|
+
let nextId = 0;
|
|
42
45
|
const observable = new Observable(() => {
|
|
43
|
-
|
|
46
|
+
const id = nextId++;
|
|
47
|
+
subscribed.push(id);
|
|
44
48
|
return () => {
|
|
45
|
-
|
|
49
|
+
unsubscribed.push(id);
|
|
46
50
|
};
|
|
47
51
|
});
|
|
48
52
|
function ObservableComponent() {
|
|
@@ -50,15 +54,36 @@ test('Strict mode should unsubscribe the source observable on unmount', () => {
|
|
|
50
54
|
return createElement(Fragment, null);
|
|
51
55
|
}
|
|
52
56
|
const { rerender } = render(createElement(StrictMode, null, createElement(ObservableComponent)));
|
|
53
|
-
expect(subscribed).
|
|
57
|
+
expect(subscribed).toEqual([0, 1]);
|
|
58
|
+
rerender(createElement(StrictMode, null, createElement('div')));
|
|
59
|
+
expect(unsubscribed).toEqual([0, 1]);
|
|
60
|
+
});
|
|
61
|
+
test('useMemoObservable should unsubscribe the source observable on unmount', () => {
|
|
62
|
+
const subscribed = [];
|
|
63
|
+
const unsubscribed = [];
|
|
64
|
+
let nextId = 0;
|
|
65
|
+
function ObservableComponent() {
|
|
66
|
+
useMemoObservable(() => {
|
|
67
|
+
return new Observable(() => {
|
|
68
|
+
const id = nextId++;
|
|
69
|
+
subscribed.push(id);
|
|
70
|
+
return () => {
|
|
71
|
+
unsubscribed.push(id);
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
}, []);
|
|
75
|
+
return createElement(Fragment, null);
|
|
76
|
+
}
|
|
77
|
+
const { rerender } = render(createElement(StrictMode, null, createElement(ObservableComponent)));
|
|
78
|
+
expect(subscribed).toEqual([0, 1]);
|
|
54
79
|
rerender(createElement(StrictMode, null, createElement('div')));
|
|
55
|
-
expect(
|
|
80
|
+
expect(unsubscribed).toEqual([0, 1]);
|
|
56
81
|
});
|
|
57
82
|
test('useAsObservable should work in strict mode', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
58
83
|
const returnedValues = [];
|
|
59
84
|
function ObservableComponent(props) {
|
|
60
85
|
const count$ = useAsObservable(props.count);
|
|
61
|
-
const count = useObservable(count
|
|
86
|
+
const count = useObservable(count$, props.count);
|
|
62
87
|
returnedValues.push(count);
|
|
63
88
|
return createElement(Fragment, null, 'ok');
|
|
64
89
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useAsObservable } from '../useAsObservable';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { renderHook } from '@testing-library/react';
|
|
4
|
+
import { test, expect } from 'vitest';
|
|
4
5
|
test('the returned observable should receive a new value when component is rendered with a new value', () => {
|
|
5
6
|
const receivedValues = [];
|
|
6
7
|
const { unmount, rerender } = renderHook((props) => {
|
|
@@ -3,6 +3,7 @@ import { useObservable } from '../useObservable';
|
|
|
3
3
|
import { asyncScheduler, Observable, of, scheduled, Subject, timer } from 'rxjs';
|
|
4
4
|
import { mapTo } from 'rxjs/operators';
|
|
5
5
|
import { createElement, Fragment } from 'react';
|
|
6
|
+
import { test, expect } from 'vitest';
|
|
6
7
|
test('should subscribe immediately on component mount and unsubscribe on component unmount', () => {
|
|
7
8
|
let subscribed = false;
|
|
8
9
|
const observable = new Observable(() => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import { FunctionComponent, ReactNode, Ref } from 'react';
|
|
3
|
-
|
|
3
|
+
type Component<Props> = (input$: Observable<Props>) => Observable<ReactNode>;
|
|
4
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
|
+
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>>;
|
|
8
8
|
export {};
|
|
@@ -4,6 +4,7 @@ import { Observable } from 'rxjs';
|
|
|
4
4
|
* Returns an observable representing updates to any React value (props, state or any other calculated value)
|
|
5
5
|
* Note: the returned observable is the same instance throughout the component lifecycle
|
|
6
6
|
* @param value
|
|
7
|
+
* @deprecated use an `of` operator and `useMemoObservable` instead for a faster, more robust and siimpler solution
|
|
7
8
|
*/
|
|
8
9
|
export declare function useAsObservable<T>(value: T): Observable<T>;
|
|
9
10
|
export declare function useAsObservable<T, K>(value: T, operator: (input: Observable<T>) => Observable<K>): Observable<K>;
|