@wener/ui
Version:
140 lines • 5.67 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSubscriptionContainer = void 0;
const react_1 = __importStar(require("react"));
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const useConstant_1 = require("./useConstant");
const immer_1 = __importDefault(require("immer"));
/// https://github.com/jamiebuilds/unstated-next/blob/master/src/unstated-next.tsx
const EMPTY = Symbol();
function createSubscriptionContainer(useHook, { isEqual } = { isEqual: (a, b) => a === b }) {
const Context = react_1.default.createContext(EMPTY);
function Provider(props) {
const subject = useConstant_1.useConstant(() => {
const initialState = props.initialState;
// type fixing
return new rxjs_1.BehaviorSubject(typeof initialState === 'function' ? initialState() : initialState);
});
const container = useConstant_1.useConstant(() => {
const setStateReal = (state) => {
let next;
if (typeof state === 'function') {
next = state(subject.getValue());
}
else {
next = state;
}
subject.next(next);
};
// handle change state when subscribe
let changing = false;
const setState = (state) => {
if (changing) {
setTimeout(() => setState(state), 0);
return;
}
changing = true;
try {
setStateReal(state);
}
finally {
changing = false;
}
};
const options = {
getState: () => subject.getValue(),
setState,
updateState(fn) {
// todo produced is immutable
setState(immer_1.default((v) => {
fn(v);
// ensure return void
}));
},
subscribe(cb) {
const subscription = subject.subscribe(cb);
return subscription.unsubscribe.bind(subscription);
},
};
return useHook(options);
});
return react_1.default.createElement(Context.Provider, { value: { container, subject } }, props.children);
}
function useContainer() {
const context = react_1.default.useContext(Context);
if (context === EMPTY) {
throw new Error('Component must be wrapped with <SubscriptionContainer.Provider>');
}
return context.container;
}
function useSelector(selector, eq = isEqual) {
const context = react_1.default.useContext(Context);
if (context === EMPTY) {
throw new Error('Component must be wrapped with <SubscriptionContainer.Provider>');
}
const subject = context.subject;
const [state, setState] = react_1.default.useState(() => selector(subject.getValue()));
react_1.useEffect(() => {
const subscription = subject.pipe(operators_1.skip(1)).subscribe((s) => {
setState((old) => {
const next = selector(s);
if (eq(old, next)) {
return old;
}
return next;
});
});
return () => subscription.unsubscribe();
}, []);
return state;
}
function useState() {
return useSelector((v) => v);
}
function useWhenValueChange(selector, cb, eq = isEqual) {
const context = react_1.default.useContext(Context);
if (context === EMPTY) {
throw new Error('Component must be wrapped with <SubscriptionContainer.Provider>');
}
const subject = context.subject;
const ref = react_1.default.useRef();
react_1.useEffect(() => {
ref.current = selector(subject.getValue());
const subscription = subject.subscribe((s) => {
const old = ref.current;
const next = selector(s);
if (!eq(old, next)) {
cb(next);
ref.current = next;
}
});
return () => subscription.unsubscribe();
}, []);
}
return { Provider, useContainer, useSelector, useState, useWhenValueChange };
}
exports.createSubscriptionContainer = createSubscriptionContainer;
//# sourceMappingURL=substated.js.map