react-rx 3.0.0-4 → 3.0.0-6

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.
Files changed (42) hide show
  1. package/LICENSE +1 -1
  2. package/dist/index.d.mts +15 -0
  3. package/dist/index.d.ts +15 -0
  4. package/dist/index.js +52 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/index.mjs +54 -0
  7. package/dist/index.mjs.map +1 -0
  8. package/package.json +25 -23
  9. package/src/__tests__/strictmode.test.ts +1 -0
  10. package/src/__tests__/useObservable.test.tsx +1 -0
  11. package/src/useObservable.ts +9 -10
  12. package/src/useObservableEvent.ts +4 -29
  13. package/dist/cjs/__tests__/strictmode.test.d.ts +0 -1
  14. package/dist/cjs/__tests__/strictmode.test.js +0 -96
  15. package/dist/cjs/__tests__/useObservable.test.d.ts +0 -1
  16. package/dist/cjs/__tests__/useObservable.test.js +0 -116
  17. package/dist/cjs/index.d.ts +0 -2
  18. package/dist/cjs/index.js +0 -18
  19. package/dist/cjs/useObservable.d.ts +0 -4
  20. package/dist/cjs/useObservable.js +0 -48
  21. package/dist/cjs/useObservableEvent.d.ts +0 -8
  22. package/dist/cjs/useObservableEvent.js +0 -52
  23. package/dist/es2015/__tests__/strictmode.test.d.ts +0 -1
  24. package/dist/es2015/__tests__/strictmode.test.js +0 -58
  25. package/dist/es2015/__tests__/useObservable.test.d.ts +0 -1
  26. package/dist/es2015/__tests__/useObservable.test.js +0 -110
  27. package/dist/es2015/index.d.ts +0 -2
  28. package/dist/es2015/index.js +0 -2
  29. package/dist/es2015/useObservable.d.ts +0 -4
  30. package/dist/es2015/useObservable.js +0 -44
  31. package/dist/es2015/useObservableEvent.d.ts +0 -8
  32. package/dist/es2015/useObservableEvent.js +0 -41
  33. package/dist/esm/__tests__/strictmode.test.d.ts +0 -1
  34. package/dist/esm/__tests__/strictmode.test.js +0 -94
  35. package/dist/esm/__tests__/useObservable.test.d.ts +0 -1
  36. package/dist/esm/__tests__/useObservable.test.js +0 -114
  37. package/dist/esm/index.d.ts +0 -2
  38. package/dist/esm/index.js +0 -2
  39. package/dist/esm/useObservable.d.ts +0 -4
  40. package/dist/esm/useObservable.js +0 -44
  41. package/dist/esm/useObservableEvent.d.ts +0 -8
  42. package/dist/esm/useObservableEvent.js +0 -46
@@ -1,48 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useObservable = void 0;
4
- var react_1 = require("react");
5
- var operators_1 = require("rxjs/operators");
6
- function getValue(value) {
7
- return typeof value === 'function' ? value() : value;
8
- }
9
- var cache = new WeakMap();
10
- function useObservable(observable, initialValue) {
11
- /**
12
- * Store the initialValue in a ref, as we don't want a changed `initialValue` to trigger a re-subscription.
13
- * But we also don't want the initialValue to be stale if the observable changes.
14
- */
15
- var initialValueRef = (0, react_1.useRef)(getValue(initialValue));
16
- /**
17
- * Ensures that the initialValue is always up-to-date in case the observable changes.
18
- */
19
- (0, react_1.useEffect)(function () {
20
- initialValueRef.current = getValue(initialValue);
21
- }, [initialValue]);
22
- var store = (0, react_1.useMemo)(function () {
23
- if (!cache.has(observable)) {
24
- var entry_1 = {
25
- snapshot: initialValueRef.current,
26
- };
27
- entry_1.observable = observable.pipe((0, operators_1.shareReplay)({ refCount: true, bufferSize: 1 }), (0, operators_1.tap)(function (value) { return (entry_1.snapshot = value); }));
28
- // Eagerly subscribe to sync set `entry.currentValue` to what the observable returns, and keep the observable alive until the component unmounts.
29
- entry_1.subscription = entry_1.observable.subscribe();
30
- cache.set(observable, entry_1);
31
- }
32
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
33
- var instance = cache.get(observable);
34
- if (instance.subscription.closed) {
35
- instance.subscription = instance.observable.subscribe();
36
- }
37
- return {
38
- subscribe: function (onStoreChange) {
39
- var subscription = instance.observable.subscribe(onStoreChange);
40
- instance.subscription.unsubscribe();
41
- return function () { return subscription.unsubscribe(); };
42
- },
43
- getSnapshot: function () { return instance.snapshot; },
44
- };
45
- }, [observable]);
46
- return (0, react_1.useSyncExternalStore)(store.subscribe, store.getSnapshot);
47
- }
48
- exports.useObservable = useObservable;
@@ -1,8 +0,0 @@
1
- import { DependencyList } from 'react';
2
- import { Observable } from 'rxjs';
3
- export declare function useObservableCallback<T, U>(fn: (arg: Observable<T>) => Observable<U>, dependencies?: DependencyList): (arg: T) => void;
4
- export declare function useObservableEvent<T, U>(fn: (arg: Observable<T>) => Observable<U>): (arg: T) => void;
5
- /**
6
- * This is a ponyfill of the upcoming `useEffectEvent` hook that'll arrive in React 19
7
- */
8
- export declare function useEffectEvent<const T extends (...args: any[]) => void>(fn: T): T;
@@ -1,52 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useEffectEvent = exports.useObservableEvent = exports.useObservableCallback = void 0;
4
- var observable_callback_1 = require("observable-callback");
5
- var react_1 = require("react");
6
- var EMPTY_DEPS = [];
7
- function useObservableCallback(fn, dependencies) {
8
- if (dependencies === void 0) { dependencies = EMPTY_DEPS; }
9
- var callbackRef = (0, react_1.useRef)();
10
- if (!callbackRef.current) {
11
- callbackRef.current = (0, observable_callback_1.observableCallback)();
12
- }
13
- var _a = callbackRef.current, calls$ = _a[0], call = _a[1];
14
- var callback = (0, react_1.useCallback)(fn, dependencies);
15
- (0, react_1.useEffect)(function () {
16
- var subscription = calls$.pipe(callback).subscribe();
17
- return function () {
18
- subscription.unsubscribe();
19
- };
20
- }, [calls$, call, callback]);
21
- return call;
22
- }
23
- exports.useObservableCallback = useObservableCallback;
24
- function useObservableEvent(fn) {
25
- var _a = (0, react_1.useState)(function () { return (0, observable_callback_1.observableCallback)(); })[0], calls$ = _a[0], call = _a[1];
26
- var callback = useEffectEvent(fn);
27
- (0, react_1.useEffect)(function () {
28
- var subscription = calls$.pipe(callback).subscribe();
29
- return function () { return subscription.unsubscribe(); };
30
- }, [callback, calls$]);
31
- return call;
32
- }
33
- exports.useObservableEvent = useObservableEvent;
34
- /**
35
- * This is a ponyfill of the upcoming `useEffectEvent` hook that'll arrive in React 19
36
- */
37
- function useEffectEvent(fn) {
38
- var ref = (0, react_1.useRef)(null);
39
- (0, react_1.useInsertionEffect)(function () {
40
- ref.current = fn;
41
- }, [fn]);
42
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
43
- return (0, react_1.useCallback)(function () {
44
- var args = [];
45
- for (var _i = 0; _i < arguments.length; _i++) {
46
- args[_i] = arguments[_i];
47
- }
48
- var f = ref.current;
49
- return f.apply(void 0, args);
50
- }, []);
51
- }
52
- exports.useEffectEvent = useEffectEvent;
@@ -1 +0,0 @@
1
- export {};
@@ -1,58 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { act, render } from '@testing-library/react';
11
- import { createElement, Fragment, StrictMode, useEffect } from 'react';
12
- import { BehaviorSubject, Observable } from 'rxjs';
13
- import { useObservable } from '../useObservable';
14
- const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
15
- // NOTE: Jest runs NODE_ENV=test by default, which enables development flags for React
16
- test('Strict mode should trigger double mount effects and re-renders', () => __awaiter(void 0, void 0, void 0, function* () {
17
- const subject = new BehaviorSubject(0);
18
- const observable = subject.asObservable();
19
- const returnedValues = [];
20
- let mountCount = 0;
21
- function ObservableComponent() {
22
- useEffect(() => {
23
- mountCount++;
24
- }, []);
25
- const observedValue = useObservable(observable);
26
- returnedValues.push(observedValue);
27
- return createElement(Fragment, null, observedValue);
28
- }
29
- render(createElement(StrictMode, null, createElement(ObservableComponent)));
30
- expect(mountCount).toEqual(2);
31
- expect(returnedValues).toEqual([0, 0]);
32
- yield wait(10);
33
- act(() => subject.next(1));
34
- expect(returnedValues).toEqual([0, 0, 1, 1]);
35
- act(() => subject.next(2));
36
- expect(returnedValues).toEqual([0, 0, 1, 1, 2, 2]);
37
- expect(mountCount).toEqual(2);
38
- }));
39
- test('Strict mode should unsubscribe the source observable on unmount', () => {
40
- const subscribed = [];
41
- const unsubscribed = [];
42
- let nextId = 0;
43
- const observable = new Observable(() => {
44
- const id = nextId++;
45
- subscribed.push(id);
46
- return () => {
47
- unsubscribed.push(id);
48
- };
49
- });
50
- function ObservableComponent() {
51
- useObservable(observable);
52
- return createElement(Fragment, null);
53
- }
54
- const { rerender } = render(createElement(StrictMode, null, createElement(ObservableComponent)));
55
- expect(subscribed).toEqual([0, 1]);
56
- rerender(createElement(StrictMode, null, createElement('div')));
57
- expect(unsubscribed).toEqual([0, 1]);
58
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,110 +0,0 @@
1
- import { act, render, renderHook } from '@testing-library/react';
2
- import { createElement, Fragment } from 'react';
3
- import { asyncScheduler, Observable, of, scheduled, Subject, timer } from 'rxjs';
4
- import { mapTo } from 'rxjs/operators';
5
- import { useObservable } from '../useObservable';
6
- test('should subscribe immediately on component mount and unsubscribe on component unmount', () => {
7
- let subscribed = false;
8
- const observable = new Observable(() => {
9
- subscribed = true;
10
- return () => {
11
- subscribed = false;
12
- };
13
- });
14
- expect(subscribed).toBe(false);
15
- const { unmount } = renderHook(() => useObservable(observable));
16
- expect(subscribed).toBe(true);
17
- unmount();
18
- expect(subscribed).toBe(false);
19
- });
20
- test('should only subscribe once when given same observable on re-renders', () => {
21
- let subscriptionCount = 0;
22
- const observable = new Observable(() => {
23
- subscriptionCount++;
24
- });
25
- expect(subscriptionCount).toBe(0);
26
- const { unmount, rerender } = renderHook(() => useObservable(observable));
27
- expect(subscriptionCount).toBe(1);
28
- rerender();
29
- expect(subscriptionCount).toBe(1);
30
- unmount();
31
- renderHook(() => useObservable(observable));
32
- expect(subscriptionCount).toBe(2);
33
- });
34
- test('should not return undefined during render if initial value is given', () => {
35
- const observable = timer(100).pipe(mapTo('emitted value'));
36
- const returnedValues = [];
37
- function ObservableComponent() {
38
- const observedValue = useObservable(observable, 'initial value');
39
- returnedValues.push(observedValue);
40
- return createElement(Fragment, null, observedValue);
41
- }
42
- render(createElement(ObservableComponent));
43
- expect(returnedValues).toEqual(expect.arrayContaining(['initial value']));
44
- });
45
- test('should not return undefined during render if observable is sync', () => {
46
- const observable = of('initial value');
47
- const returnedValues = [];
48
- function ObservableComponent() {
49
- const observedValue = useObservable(observable);
50
- returnedValues.push(observedValue);
51
- return createElement(Fragment, null, observedValue);
52
- }
53
- render(createElement(ObservableComponent));
54
- expect(returnedValues).toEqual(expect.arrayContaining(['initial value']));
55
- });
56
- test('should return undefined during first render if observable is async', () => {
57
- const observable = scheduled('async value', asyncScheduler);
58
- const returnedValues = [];
59
- function ObservableComponent() {
60
- const observedValue = useObservable(observable);
61
- returnedValues.push(observedValue);
62
- return createElement(Fragment, null, observedValue);
63
- }
64
- render(createElement(ObservableComponent));
65
- expect(returnedValues).toEqual(expect.arrayContaining([undefined]));
66
- });
67
- test('should have sync values from an observable as initial value', () => {
68
- const observable = of('something sync');
69
- const { result } = renderHook(() => useObservable(observable));
70
- expect(result.current).toBe('something sync');
71
- });
72
- test('should have undefined as initial value from delayed observables', () => {
73
- const { result, unmount } = renderHook(() => useObservable(scheduled('something async', asyncScheduler)));
74
- expect(result.current).toBeUndefined();
75
- unmount();
76
- });
77
- test('should have passed initialValue as initial value from delayed observables', () => {
78
- const { result, unmount } = renderHook(() => useObservable(scheduled('something async', asyncScheduler), 'initial'));
79
- expect(result.current).toBe('initial');
80
- unmount();
81
- });
82
- test('should update with values from observables', () => {
83
- const values$ = new Subject();
84
- const { result, unmount } = renderHook(() => useObservable(values$));
85
- expect(result.current).toBe(undefined);
86
- act(() => values$.next('something'));
87
- expect(result.current).toBe('something');
88
- act(() => values$.next('otherthing'));
89
- expect(result.current).toBe('otherthing');
90
- unmount();
91
- });
92
- test('should re-subscribe when receiving a new observable', () => {
93
- const first$ = new Subject();
94
- const second$ = new Subject();
95
- let current$ = first$;
96
- const { result, rerender, unmount } = renderHook(() => useObservable(current$, '!!initial!!'));
97
- act(() => first$.next('first 1'));
98
- expect(result.current).toBe('first 1');
99
- current$ = second$;
100
- rerender();
101
- // since observable #2 hasn't emitted a value yet, we should use the initial value
102
- expect(result.current).toBe('!!initial!!');
103
- // Now we should be subscribed to second$ and it's emission should be returned
104
- act(() => second$.next('second 1'));
105
- expect(result.current).toBe('second 1');
106
- // we should no longer be subscribed to the first and ignore any emissions
107
- act(() => first$.next('first 2'));
108
- expect(result.current).toBe('second 1');
109
- unmount();
110
- });
@@ -1,2 +0,0 @@
1
- export * from './useObservable';
2
- export * from './useObservableEvent';
@@ -1,2 +0,0 @@
1
- export * from './useObservable';
2
- export * from './useObservableEvent';
@@ -1,4 +0,0 @@
1
- import type { Observable } from 'rxjs';
2
- export declare function useObservable<ObservableType extends Observable<any>>(observable: ObservableType, initialValue?: UnboxObservable<ObservableType> | (() => UnboxObservable<ObservableType>)): UnboxObservable<ObservableType>;
3
- type UnboxObservable<T> = T extends Observable<infer U> ? U : never;
4
- export {};
@@ -1,44 +0,0 @@
1
- import { useEffect, useMemo, useRef, useSyncExternalStore } from 'react';
2
- import { shareReplay, tap } from 'rxjs/operators';
3
- function getValue(value) {
4
- return typeof value === 'function' ? value() : value;
5
- }
6
- const cache = new WeakMap();
7
- export function useObservable(observable, initialValue) {
8
- /**
9
- * Store the initialValue in a ref, as we don't want a changed `initialValue` to trigger a re-subscription.
10
- * But we also don't want the initialValue to be stale if the observable changes.
11
- */
12
- const initialValueRef = useRef(getValue(initialValue));
13
- /**
14
- * Ensures that the initialValue is always up-to-date in case the observable changes.
15
- */
16
- useEffect(() => {
17
- initialValueRef.current = getValue(initialValue);
18
- }, [initialValue]);
19
- const store = useMemo(() => {
20
- if (!cache.has(observable)) {
21
- const entry = {
22
- snapshot: initialValueRef.current,
23
- };
24
- entry.observable = observable.pipe(shareReplay({ refCount: true, bufferSize: 1 }), tap((value) => (entry.snapshot = value)));
25
- // Eagerly subscribe to sync set `entry.currentValue` to what the observable returns, and keep the observable alive until the component unmounts.
26
- entry.subscription = entry.observable.subscribe();
27
- cache.set(observable, entry);
28
- }
29
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
30
- const instance = cache.get(observable);
31
- if (instance.subscription.closed) {
32
- instance.subscription = instance.observable.subscribe();
33
- }
34
- return {
35
- subscribe: (onStoreChange) => {
36
- const subscription = instance.observable.subscribe(onStoreChange);
37
- instance.subscription.unsubscribe();
38
- return () => subscription.unsubscribe();
39
- },
40
- getSnapshot: () => instance.snapshot,
41
- };
42
- }, [observable]);
43
- return useSyncExternalStore(store.subscribe, store.getSnapshot);
44
- }
@@ -1,8 +0,0 @@
1
- import { DependencyList } from 'react';
2
- import { Observable } from 'rxjs';
3
- export declare function useObservableCallback<T, U>(fn: (arg: Observable<T>) => Observable<U>, dependencies?: DependencyList): (arg: T) => void;
4
- export declare function useObservableEvent<T, U>(fn: (arg: Observable<T>) => Observable<U>): (arg: T) => void;
5
- /**
6
- * This is a ponyfill of the upcoming `useEffectEvent` hook that'll arrive in React 19
7
- */
8
- export declare function useEffectEvent<const T extends (...args: any[]) => void>(fn: T): T;
@@ -1,41 +0,0 @@
1
- import { observableCallback } from 'observable-callback';
2
- import { useCallback, useEffect, useInsertionEffect, useRef, useState } from 'react';
3
- const EMPTY_DEPS = [];
4
- export function useObservableCallback(fn, dependencies = EMPTY_DEPS) {
5
- const callbackRef = useRef();
6
- if (!callbackRef.current) {
7
- callbackRef.current = observableCallback();
8
- }
9
- const [calls$, call] = callbackRef.current;
10
- const callback = useCallback(fn, dependencies);
11
- useEffect(() => {
12
- const subscription = calls$.pipe(callback).subscribe();
13
- return () => {
14
- subscription.unsubscribe();
15
- };
16
- }, [calls$, call, callback]);
17
- return call;
18
- }
19
- export function useObservableEvent(fn) {
20
- const [[calls$, call]] = useState(() => observableCallback());
21
- const callback = useEffectEvent(fn);
22
- useEffect(() => {
23
- const subscription = calls$.pipe(callback).subscribe();
24
- return () => subscription.unsubscribe();
25
- }, [callback, calls$]);
26
- return call;
27
- }
28
- /**
29
- * This is a ponyfill of the upcoming `useEffectEvent` hook that'll arrive in React 19
30
- */
31
- export function useEffectEvent(fn) {
32
- const ref = useRef(null);
33
- useInsertionEffect(() => {
34
- ref.current = fn;
35
- }, [fn]);
36
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
- return useCallback((...args) => {
38
- const f = ref.current;
39
- return f(...args);
40
- }, []);
41
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,94 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- var __generator = (this && this.__generator) || function (thisArg, body) {
11
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
- function verb(n) { return function (v) { return step([n, v]); }; }
14
- function step(op) {
15
- if (f) throw new TypeError("Generator is already executing.");
16
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
- 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;
18
- if (y = 0, t) op = [op[0] & 2, t.value];
19
- switch (op[0]) {
20
- case 0: case 1: t = op; break;
21
- case 4: _.label++; return { value: op[1], done: false };
22
- case 5: _.label++; y = op[1]; op = [0]; continue;
23
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
- default:
25
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
- if (t[2]) _.ops.pop();
30
- _.trys.pop(); continue;
31
- }
32
- op = body.call(thisArg, _);
33
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
- }
36
- };
37
- import { act, render } from '@testing-library/react';
38
- import { createElement, Fragment, StrictMode, useEffect } from 'react';
39
- import { BehaviorSubject, Observable } from 'rxjs';
40
- import { useObservable } from '../useObservable';
41
- var wait = function (ms) { return new Promise(function (resolve) { return setTimeout(resolve, ms); }); };
42
- // NOTE: Jest runs NODE_ENV=test by default, which enables development flags for React
43
- test('Strict mode should trigger double mount effects and re-renders', function () { return __awaiter(void 0, void 0, void 0, function () {
44
- function ObservableComponent() {
45
- useEffect(function () {
46
- mountCount++;
47
- }, []);
48
- var observedValue = useObservable(observable);
49
- returnedValues.push(observedValue);
50
- return createElement(Fragment, null, observedValue);
51
- }
52
- var subject, observable, returnedValues, mountCount;
53
- return __generator(this, function (_a) {
54
- switch (_a.label) {
55
- case 0:
56
- subject = new BehaviorSubject(0);
57
- observable = subject.asObservable();
58
- returnedValues = [];
59
- mountCount = 0;
60
- render(createElement(StrictMode, null, createElement(ObservableComponent)));
61
- expect(mountCount).toEqual(2);
62
- expect(returnedValues).toEqual([0, 0]);
63
- return [4 /*yield*/, wait(10)];
64
- case 1:
65
- _a.sent();
66
- act(function () { return subject.next(1); });
67
- expect(returnedValues).toEqual([0, 0, 1, 1]);
68
- act(function () { return subject.next(2); });
69
- expect(returnedValues).toEqual([0, 0, 1, 1, 2, 2]);
70
- expect(mountCount).toEqual(2);
71
- return [2 /*return*/];
72
- }
73
- });
74
- }); });
75
- test('Strict mode should unsubscribe the source observable on unmount', function () {
76
- var subscribed = [];
77
- var unsubscribed = [];
78
- var nextId = 0;
79
- var observable = new Observable(function () {
80
- var id = nextId++;
81
- subscribed.push(id);
82
- return function () {
83
- unsubscribed.push(id);
84
- };
85
- });
86
- function ObservableComponent() {
87
- useObservable(observable);
88
- return createElement(Fragment, null);
89
- }
90
- var rerender = render(createElement(StrictMode, null, createElement(ObservableComponent))).rerender;
91
- expect(subscribed).toEqual([0, 1]);
92
- rerender(createElement(StrictMode, null, createElement('div')));
93
- expect(unsubscribed).toEqual([0, 1]);
94
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,114 +0,0 @@
1
- import { act, render, renderHook } from '@testing-library/react';
2
- import { createElement, Fragment } from 'react';
3
- import { asyncScheduler, Observable, of, scheduled, Subject, timer } from 'rxjs';
4
- import { mapTo } from 'rxjs/operators';
5
- import { useObservable } from '../useObservable';
6
- test('should subscribe immediately on component mount and unsubscribe on component unmount', function () {
7
- var subscribed = false;
8
- var observable = new Observable(function () {
9
- subscribed = true;
10
- return function () {
11
- subscribed = false;
12
- };
13
- });
14
- expect(subscribed).toBe(false);
15
- var unmount = renderHook(function () { return useObservable(observable); }).unmount;
16
- expect(subscribed).toBe(true);
17
- unmount();
18
- expect(subscribed).toBe(false);
19
- });
20
- test('should only subscribe once when given same observable on re-renders', function () {
21
- var subscriptionCount = 0;
22
- var observable = new Observable(function () {
23
- subscriptionCount++;
24
- });
25
- expect(subscriptionCount).toBe(0);
26
- var _a = renderHook(function () { return useObservable(observable); }), unmount = _a.unmount, rerender = _a.rerender;
27
- expect(subscriptionCount).toBe(1);
28
- rerender();
29
- expect(subscriptionCount).toBe(1);
30
- unmount();
31
- renderHook(function () { return useObservable(observable); });
32
- expect(subscriptionCount).toBe(2);
33
- });
34
- test('should not return undefined during render if initial value is given', function () {
35
- var observable = timer(100).pipe(mapTo('emitted value'));
36
- var returnedValues = [];
37
- function ObservableComponent() {
38
- var observedValue = useObservable(observable, 'initial value');
39
- returnedValues.push(observedValue);
40
- return createElement(Fragment, null, observedValue);
41
- }
42
- render(createElement(ObservableComponent));
43
- expect(returnedValues).toEqual(expect.arrayContaining(['initial value']));
44
- });
45
- test('should not return undefined during render if observable is sync', function () {
46
- var observable = of('initial value');
47
- var returnedValues = [];
48
- function ObservableComponent() {
49
- var observedValue = useObservable(observable);
50
- returnedValues.push(observedValue);
51
- return createElement(Fragment, null, observedValue);
52
- }
53
- render(createElement(ObservableComponent));
54
- expect(returnedValues).toEqual(expect.arrayContaining(['initial value']));
55
- });
56
- test('should return undefined during first render if observable is async', function () {
57
- var observable = scheduled('async value', asyncScheduler);
58
- var returnedValues = [];
59
- function ObservableComponent() {
60
- var observedValue = useObservable(observable);
61
- returnedValues.push(observedValue);
62
- return createElement(Fragment, null, observedValue);
63
- }
64
- render(createElement(ObservableComponent));
65
- expect(returnedValues).toEqual(expect.arrayContaining([undefined]));
66
- });
67
- test('should have sync values from an observable as initial value', function () {
68
- var observable = of('something sync');
69
- var result = renderHook(function () { return useObservable(observable); }).result;
70
- expect(result.current).toBe('something sync');
71
- });
72
- test('should have undefined as initial value from delayed observables', function () {
73
- var _a = renderHook(function () {
74
- return useObservable(scheduled('something async', asyncScheduler));
75
- }), result = _a.result, unmount = _a.unmount;
76
- expect(result.current).toBeUndefined();
77
- unmount();
78
- });
79
- test('should have passed initialValue as initial value from delayed observables', function () {
80
- var _a = renderHook(function () {
81
- return useObservable(scheduled('something async', asyncScheduler), 'initial');
82
- }), result = _a.result, unmount = _a.unmount;
83
- expect(result.current).toBe('initial');
84
- unmount();
85
- });
86
- test('should update with values from observables', function () {
87
- var values$ = new Subject();
88
- var _a = renderHook(function () { return useObservable(values$); }), result = _a.result, unmount = _a.unmount;
89
- expect(result.current).toBe(undefined);
90
- act(function () { return values$.next('something'); });
91
- expect(result.current).toBe('something');
92
- act(function () { return values$.next('otherthing'); });
93
- expect(result.current).toBe('otherthing');
94
- unmount();
95
- });
96
- test('should re-subscribe when receiving a new observable', function () {
97
- var first$ = new Subject();
98
- var second$ = new Subject();
99
- var current$ = first$;
100
- var _a = renderHook(function () { return useObservable(current$, '!!initial!!'); }), result = _a.result, rerender = _a.rerender, unmount = _a.unmount;
101
- act(function () { return first$.next('first 1'); });
102
- expect(result.current).toBe('first 1');
103
- current$ = second$;
104
- rerender();
105
- // since observable #2 hasn't emitted a value yet, we should use the initial value
106
- expect(result.current).toBe('!!initial!!');
107
- // Now we should be subscribed to second$ and it's emission should be returned
108
- act(function () { return second$.next('second 1'); });
109
- expect(result.current).toBe('second 1');
110
- // we should no longer be subscribed to the first and ignore any emissions
111
- act(function () { return first$.next('first 2'); });
112
- expect(result.current).toBe('second 1');
113
- unmount();
114
- });
@@ -1,2 +0,0 @@
1
- export * from './useObservable';
2
- export * from './useObservableEvent';
package/dist/esm/index.js DELETED
@@ -1,2 +0,0 @@
1
- export * from './useObservable';
2
- export * from './useObservableEvent';
@@ -1,4 +0,0 @@
1
- import type { Observable } from 'rxjs';
2
- export declare function useObservable<ObservableType extends Observable<any>>(observable: ObservableType, initialValue?: UnboxObservable<ObservableType> | (() => UnboxObservable<ObservableType>)): UnboxObservable<ObservableType>;
3
- type UnboxObservable<T> = T extends Observable<infer U> ? U : never;
4
- export {};