| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- 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
|