@guanghechen/react-viewmodel
Version:
212 lines (199 loc) • 7.36 kB
JavaScript
;
var viewmodel = require('@guanghechen/viewmodel');
var React = require('react');
var subscriber = require('@guanghechen/subscriber');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
let didWarnOld18Alpha = false;
let didWarnUncachedGetSnapshot = false;
function useSyncExternalStore$2(subscribe, getSnapshot, _getServerSnapshot) {
if (process.env.NODE_ENV === 'development') {
if (!didWarnOld18Alpha) {
if (React__namespace.startTransition !== undefined) {
didWarnOld18Alpha = true;
console.error('You are using an outdated, pre-release alpha of React 18 that ' +
'does not support useSyncExternalStore. The ' +
'use-sync-external-store shim will not work correctly. Upgrade ' +
'to a newer pre-release.');
}
}
}
const value = getSnapshot();
if (process.env.NODE_ENV === 'development') {
if (!didWarnUncachedGetSnapshot) {
const cachedValue = getSnapshot();
if (!Object.is(value, cachedValue)) {
console.error('The result of getSnapshot should be cached to avoid an infinite loop');
didWarnUncachedGetSnapshot = true;
}
}
}
const [{ inst }, forceUpdate] = React.useState({ inst: { value, getSnapshot } });
React.useLayoutEffect(() => {
inst.value = value;
inst.getSnapshot = getSnapshot;
if (checkIfSnapshotChanged(inst)) {
forceUpdate({ inst });
}
}, [subscribe, value, getSnapshot]);
React.useEffect(() => {
if (checkIfSnapshotChanged(inst)) {
forceUpdate({ inst });
}
const handleStoreChange = () => {
if (checkIfSnapshotChanged(inst)) {
forceUpdate({ inst });
}
};
return subscribe(handleStoreChange);
}, [subscribe]);
React.useDebugValue(value);
return value;
}
function checkIfSnapshotChanged(inst) {
const latestGetSnapshot = inst.getSnapshot;
const prevValue = inst.value;
try {
const nextValue = latestGetSnapshot();
return !Object.is(prevValue, nextValue);
}
catch (_) {
return true;
}
}
function useSyncExternalStore$1(_subscribe, getSnapshot, _getServerSnapshot) {
return getSnapshot();
}
const canUseDOM = !!(typeof window !== 'undefined' &&
typeof window.document !== 'undefined' &&
typeof window.document.createElement !== 'undefined');
const shim = canUseDOM ? useSyncExternalStore$2 : useSyncExternalStore$1;
const builtin = React__namespace.useSyncExternalStore;
const useSyncExternalStore = builtin ? builtin : shim;
function useComputed(computed$) {
const { getSnapshot, getServerSnapshot, subscribeStateChange } = computed$;
return useSyncExternalStore(subscribeStateChange, getSnapshot, getServerSnapshot);
}
function useObserveKey(collection, key) {
const [state, setState] = React.useState(collection.get(key));
React.useEffect(() => {
const subscriber$1 = new subscriber.Subscriber({
onNext: v => setState(v),
});
const unsubscribable = collection.subscribeKey(key, subscriber$1);
return () => {
subscriber$1.dispose();
unsubscribable.unsubscribe();
};
}, [collection, key]);
return state;
}
function useObserveSignal(viewmodel, keys) {
const { ticker } = React.useMemo(() => viewmodel.ticker(keys), [viewmodel, ...keys]);
const [signal, setSignal] = React.useState(0);
React.useEffect(() => {
const subscriber$1 = new subscriber.Subscriber({
onNext: () => setSignal(s => s + 1),
});
const unsubscribable = ticker.subscribe(subscriber$1);
return () => {
subscriber$1.dispose();
unsubscribable.unsubscribe();
};
}, [ticker]);
return signal;
}
function useStateValue(state$) {
const { getSnapshot, getServerSnapshot, subscribeStateChange } = state$;
return useSyncExternalStore(subscribeStateChange, getSnapshot, getServerSnapshot);
}
function useSetState(state$) {
const { setState } = state$;
return setState;
}
function useState(state$) {
const { getSnapshot, getServerSnapshot, subscribeStateChange, setState } = state$;
const state = useSyncExternalStore(subscribeStateChange, getSnapshot, getServerSnapshot);
return [state, setState];
}
function useReactState(state$) {
const { getSnapshot, getServerSnapshot, subscribeStateChange, updateState } = state$;
const state = useSyncExternalStore(subscribeStateChange, getSnapshot, getServerSnapshot);
return [state, updateState];
}
function useToggleState(state$) {
const { setState } = state$;
return React.useCallback(() => {
setState(flag => !flag);
}, [setState]);
}
const useViewModel = (fn) => {
const ref = React.useRef(null);
const [_, setTick] = React.useState(0);
const fnRef = React.useRef(fn);
fnRef.current = fn;
React.useEffect(() => {
let cancelled = false;
if (!ref.current) {
const promise = Promise.resolve(fnRef.current());
void promise
.then((viewmodel) => {
ref.current = viewmodel;
const name = viewmodel.name || viewmodel.constructor.name;
console.log(`[useViewModel] creating ${name}.`);
if (!cancelled) {
setTick(c => c + 1);
}
})
.catch(error => {
ref.current = null;
console.log('[useViewModel] failed. error:', error);
if (!cancelled) {
setTick(c => c + 1);
}
});
}
return () => {
cancelled = true;
const viewmodel = ref.current;
if (!viewmodel)
return;
const name = viewmodel.name || viewmodel.constructor.name;
console.log(`[useViewModel] disposing ${name}.`);
ref.current = null;
viewmodel.dispose();
};
}, []);
return ref.current;
};
exports.useComputed = useComputed;
exports.useObserveKey = useObserveKey;
exports.useObserveSignal = useObserveSignal;
exports.useReactState = useReactState;
exports.useSetState = useSetState;
exports.useState = useState;
exports.useStateValue = useStateValue;
exports.useSyncExternalStore = useSyncExternalStore;
exports.useToggleState = useToggleState;
exports.useViewModel = useViewModel;
Object.keys(viewmodel).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
enumerable: true,
get: function () { return viewmodel[k]; }
});
});