Closed dmaskasky closed 11 months ago
I haven't considered such an API. Maybe because I'd simply do proxy.value++
.
is this repo specifically intended for syncing a jotai atom with a valtio proxy?
That was my motivation, but it's not limited if someone else has an idea and can take the lead.
On the other hand, if we were able to create jotai-effect
, this wouldn't be very useful because we can do it with jotai-effect
, I guess.
Welcome back Dai-Shi 😌.
Since state lives in the store in Jotai, this makes it unavailable to convert to a Valtio proxy.
The current api for jotai-valtio allows for Valtio -> Jotai
but not Jotai -> Valtio
. This is my motivation for introducing a new api. I think only withProxyEffect
would be necessary to achieve Jotai -> Valtio
.
Can't atomEffect
https://github.com/pmndrs/jotai/discussions/2136 do Jotai -> Valtio
?
The main issue I've been having with using atomEffect this way is in supporting the initial read of the withProxyEffect atom. Because, atomEffects are designed to run async (post read). But I'll keep trying to get this to work.
Here's a simple prototype of withProxyEffect. The main drawback is that the initial read returns undefined
. I have a more complex example that fixes this, but it is suffering from another strange bug.
const defaultOptions: Required<ValtioOptions<any>> = {
sync: true,
proxyFn: proxy,
};
type ProxyStore<Value> = {
proxyState: ProxyState<Value>;
unsubscribe: () => void;
};
export function withProxyEffect<Value>(
atomToSync: WritableAtom<Value, [SetStateAction<Value>], any>,
options: ValtioOptions<Value> = defaultOptions
) {
const proxyAtom = makeProxyAtom(atomToSync, options);
return makeWithProxyEffect(proxyAtom, atomToSync);
}
export function makeWithProxyEffect<Value>(
proxyAtom: WritableAtom<ProxyStore<Value> | null, [boolean | ProxyStore<Value> | null], void>,
atomToSync: WritableAtom<Value, [SetStateAction<Value>], any>
) {
const derivedAtom = atom((get) => {
const proxyStore = get(proxyAtom);
const state = get(atomToSync);
if (proxyStore === null) return;
const { proxyState } = proxyStore;
if (state !== snapshot(proxyState).value) {
proxyState.value = state as Value;
}
return createProxyWrapper(proxyState);
});
return derivedAtom;
}
export function makeProxyAtom<Value>(
atomToSync: WritableAtom<Value, [SetStateAction<Value>], any>,
options: ValtioOptions<Value> = defaultOptions
) {
const { sync, proxyFn } = { ...defaultOptions, ...options };
const proxyAtom = atom<null | ProxyStore<Value>, [boolean | null | ProxyStore<Value>], void>(
null,
(get, set, isInit) => {
if (isInit) {
const value = get(atomToSync);
const proxyState = proxyFn({ value }) as ProxyState<Value>;
const unsubscribe = subscribe(
proxyState,
() => {
const { value } = snapshot(proxyState);
if (value !== get(atomToSync)) {
set(atomToSync, value as Value);
}
},
sync
);
set(proxyAtom, { proxyState, unsubscribe });
} else {
get(proxyAtom)?.unsubscribe?.();
}
}
);
proxyAtom.onMount = (init) => {
init(true);
return () => init(false);
};
return proxyAtom;
}
function createProxyWrapper<T>(state: ProxyState<T>): ProxyState<T> {
return new Proxy(state, {
get(target, property: string) {
return target[property as keyof ProxyState<T>] as T;
},
set(target, property: string, value: any) {
if (property === 'value') {
target[property] = value;
return true;
}
return false;
},
});
}
Hmm, I wonder if Jotai -> Valtio
makes sense for multiple provider use case.
ex: https://twitter.com/dai_shi/status/1447892237753278466
Hmm, I wonder if
Jotai -> Valtio
makes sense for multiple provider use case. ex: https://twitter.com/dai_shi/status/1447892237753278466
The proxy is treated as Jotai state so it cannot be accessed outside of the react component tree. Does this feel natural? ex: https://codesandbox.io/s/pensive-wood-lspvpd
Perhaps its better to think of this utility as "updating Jotai atoms like how Valtio does it", rather than "converting Jotai into Valtio".
Perhaps its better to think of this utility as "updating Jotai atoms like how Valtio does it", rather than "converting Jotai into Valtio".
Yeah, that makes sense.
Would something like this fit in jotai-valtio?
It's different from the original motivation, but it's another style of integration, so it should fit.
I wouldn't mind adding it here if you keep maintaining it, but my suspicion is whether if people would use it and if I'd actually recommend it, because if you design Jotai atoms "atomic", deep proxy updating shouldn't be necessary.
I've submitted PR https://github.com/jotaijs/jotai-valtio/pull/5. Happy to continue this discussion in the PR. Closing this ticket for now.
I'm not sure if this is the right place, but from the repo name only I wanted to do something like this.
Was this API considered, or is this repo specifically intended for syncing a jotai atom with a valtio proxy?
Example: https://codesandbox.io/s/jotai-demo-forked-skvmhs
What do you think? Would something like this fit in jotai-valtio?