jotai-valtio
Version:
82 lines (81 loc) • 2.79 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.mutableAtom = mutableAtom;
const vanilla_1 = require("jotai/vanilla");
const vanilla_2 = require("valtio/vanilla");
const utils_1 = require("valtio/vanilla/utils");
function mutableAtom(initialValue, options = defaultOptions) {
const valueAtom = (0, vanilla_1.atom)({ value: initialValue });
if (process.env.NODE_ENV !== 'production') {
valueAtom.debugPrivate = true;
}
const { proxyFn } = { ...defaultOptions, ...options };
const storeAtom = (0, vanilla_1.atom)((_get, { setSelf }) => {
const store = {
proxyState: createProxyState(() => store),
getValue: () => setSelf({ type: 'getValue' }),
setValue: (value) => setSelf({ type: 'setValue', payload: value }),
};
return store;
}, (get, set, action) => {
if (action.type === 'setValue') {
set(valueAtom, { value: action.payload });
}
else if (action.type === 'getValue') {
return get(valueAtom).value;
}
});
if (process.env.NODE_ENV !== 'production') {
storeAtom.debugPrivate = true;
}
/**
* sync the proxy state with the atom
*/
function onChange(getStore) {
return () => {
const { proxyState, getValue, setValue } = getStore();
const { value } = (0, vanilla_2.snapshot)(proxyState);
if (!Object.is(value, getValue())) {
setValue(value);
}
};
}
/**
* create the proxy state and subscribe to it
*/
function createProxyState(getStore) {
const proxyState = proxyFn({ value: (0, utils_1.deepClone)(initialValue) });
// We never unsubscribe, but it's garbage collectable.
(0, vanilla_2.subscribe)(proxyState, onChange(getStore), true);
return proxyState;
}
/**
* wrap the proxy state in a proxy to ensure rerender on value change
*/
function wrapProxyState(proxyState) {
return new Proxy(proxyState, {
get(target, property) {
return target[property];
},
set(target, property, value) {
if (property === 'value') {
target[property] = value;
return true;
}
return false;
},
});
}
/**
* create an atom that returns the proxy state
*/
const proxyEffectAtom = (0, vanilla_1.atom)((get) => {
get(valueAtom); // subscribe to value updates
const store = get(storeAtom);
return wrapProxyState(store.proxyState);
});
return proxyEffectAtom;
}
const defaultOptions = {
proxyFn: vanilla_2.proxy,
};