var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; import React, { useEffect, useState, createContext, useMemo, useContext, useCallback, useRef, } from 'react'; import { BehaviorSubject } from 'rxjs'; import { RediError } from '@wendellhu/redi'; /** * unwrap an observable value, return it to the component for rendering, and * trigger re-render when value changes * * **IMPORTANT**. Parent and child components better not subscribe to the same * observable, otherwise unnecessary re-render would be triggered. Instead, the * top-most component should subscribe and pass value of the observable to * its offspring, by props or context. Please consider using `useDependencyContext` and * `useDependencyContextValue` in this case. * * @deprecated Please use `useObservable` instead. */ export function useDependencyValue(depValue$, defaultValue) { var firstValue = depValue$ instanceof BehaviorSubject && typeof defaultValue === 'undefined' ? depValue$.getValue() : defaultValue; var _a = useState(firstValue), value = _a[0], setValue = _a[1]; useEffect(function () { var subscription = depValue$.subscribe(function (val) { return setValue(val); }); return function () { return subscription.unsubscribe(); }; }, [depValue$]); return value; } function unwrap(o) { if (typeof o === 'function') { return o(); } return o; } /** * Subscribe to an observable and return its value. The component will re-render when the observable emits a new value. * * @param observable An observable or a function that returns an observable * @param defaultValue The default value of the observable. It the `observable` can omit an initial value, this value will be neglected. * @param shouldHaveSyncValue If the observable should have a sync value. If it does not have a sync value, an error will be thrown. * @param deps A dependency array to decide if we should re-subscribe when the `observable` is a function. * @returns */ export function useObservable(observable, defaultValue, shouldHaveSyncValue, deps) { if (typeof observable === 'function' && !deps) { throw new RediError("Expected deps to be provided when observable is a function!"); } var observableRef = useRef(null); var initializedRef = useRef(false); // eslint-disable-next-line react-hooks/exhaustive-deps var destObservable = useMemo(function () { return observable; }, __spreadArray([], (typeof deps !== 'undefined' ? deps : [observable]), true)); // This state is only for trigger React to re-render. We do not use `setValue` directly because it may cause // memory leaking. var _a = useState(0), _ = _a[0], setRenderCounter = _a[1]; var valueRef = useRef((function () { var innerDefaultValue; if (destObservable) { var sub = unwrap(destObservable).subscribe(function (value) { initializedRef.current = true; innerDefaultValue = value; }); sub.unsubscribe(); } return innerDefaultValue !== null && innerDefaultValue !== void 0 ? innerDefaultValue : defaultValue; })()); useEffect(function () { var subscription = null; if (destObservable) { observableRef.current = unwrap(destObservable); subscription = observableRef.current.subscribe(function (value) { valueRef.current = value; setRenderCounter(function (prev) { return prev + 1; }); }); } return function () { return subscription === null || subscription === void 0 ? void 0 : subscription.unsubscribe(); }; }, [destObservable]); if (shouldHaveSyncValue && !initializedRef.current) { throw new Error('Expect `shouldHaveSyncValue` but not getting a sync value!'); } return valueRef.current; } /** * subscribe to a signal that emits whenever data updates and re-render * * @param update$ a signal that the data the functional component depends has updated */ export function useUpdateBinder(update$) { var _a = useState(0), dumpSet = _a[1]; useEffect(function () { var subscription = update$.subscribe(function () { return dumpSet(function (prev) { return prev + 1; }); }); return function () { return subscription.unsubscribe(); }; }, []); } var DepValueMapProvider = new WeakMap(); /** * subscribe to an observable value from a service, creating a context for it so * it child component won't have to subscribe again and cause unnecessary */ export function useDependencyContext(depValue$, defaultValue) { var depRef = useRef(undefined); var value = useDependencyValue(depValue$, defaultValue); var Context = useMemo(function () { return createContext(value); }, [depValue$]); var Provider = useCallback(function (props) { return React.createElement(Context.Provider, { value: value }, props.children); }, [depValue$, value]); if (depRef.current !== depValue$) { if (depRef.current) { DepValueMapProvider.delete(depRef.current); } depRef.current = depValue$; DepValueMapProvider.set(depValue$, Context); } return { Provider: Provider, value: value, }; } export function useDependencyContextValue(depValue$) { var context = DepValueMapProvider.get(depValue$); if (!context) { throw new RediError("try to read context value but no ancestor component subscribed it."); } return useContext(context); } //# sourceMappingURL=reactRx.js.map