-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dynamic / parameterized optics #15
Comments
Hmm, something like this maybe: const dynamicFocusAtom =
<T extends object>(baseAtom: PrimitiveAtom<T>) =>
<Key extends keyof T>(key: Key): PrimitiveAtom<T[Key]> =>
focusAtom(baseAtom, optic => optic.prop(key))
const baseAtom = atom({ a: 5, b: 'string' } as const) // PrimitiveAtom<{a: number}>
const atomDeriver = dynamicFocusAtom(baseAtom)
const focusA = atomDeriver('a') // PrimitiveAtom<5>
const focusB = atomDeriver('b') // PrimitiveAtom<'string'> Does that work? |
I wonder if From Jotai's perspective, #15 (comment) If that works, it works. |
Hey @dai-shi I actually have the same use case. I'm not sure if #15 (comment) addresses it, because I'd like to pass in a prop when calling the setter, not when declaring the atom or wrapping it in useAtom. Specifically, I'd like to call my focus atom setter from inside an Ably callback. My atom is an object of dynamic keys, for example
and I'd like to be able to update specific fields using a path I'm creating from inside the callback because I'm consuming ably messages that contain metadata from which I can construct my path.
I can't declare |
@seanyboy49 I'm not sure if I follow 100%, but it sounds like you can use a write-only atom or useAtomCallback. const setValueWithPath = useSetAtom(useMemo(() => atom(null, (get, set, { path, updatedValue }) => {
const a = focusAtom(atom, (optic) => optic.path(path))
set(a, updatedValue)
}), []))
const { connectionError, channelError } = useChannel(ablyChannelId, (message: Ably.Types.Message) => {
const path = getPathFromMessage(message)
setValueWithPath({ path, updatedValue: Math.random() }) |
@dai-shi thanks for the prompt response! Yes, that does the trick! const largeAtom = atom({})
const useJotaiDerived = (path?: string) => {
const read = useCallback(
(get: Getter) => {
const val = get(largeAtom)
if (!path) return val
const optic = O.optic().path(path)
return O.get(optic)(val)
},
[path],
)
const write = useCallback((get: Getter, set: Setter, newValue: { path: string; value: string }) => {
set(largeAtom, (prev) => {
const { path, value } = newValue
const optic = O.optic().path(path)
const updated = O.set(optic)(value)(prev)
return updated
})
}, [])
const derivedTraitInstance = useAtom(useMemo(() => atom(read, write), [read, write]))
return derivedTraitInstance
} |
Is it possible to create a generic optic or selector for an object, similar to how
splitAtom
works for arrays?For both
selectAtom
andfocusAtom
, the examples on the website work nicely if you know the property you want in advance, but sometimes you do not.Is it possible for us to add another primitive that does something like the following?
This would allow passing more narrowly scoped atoms down to children, but I'm not sure if we could expect any reasonable performance gains if we don't know the accessor in advance. Would be curious to hear about expected perf gains for
splitAtom
and maybe we can infer from that.The text was updated successfully, but these errors were encountered: