-
-
Notifications
You must be signed in to change notification settings - Fork 571
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
Is it possible to read an atom's current state without using useAtom? #60
Comments
Quotting from #13, whether it's not possible or not covered by this library:
|
But what about atom.read, atom.write ? |
They are just definitions, so you can't call them.
Correct. Just think it like the normal So, here's the workaround: const Component = () => {
const authStateRef = useRef()
const authState = useAtom(authAtom) // or useState(...)
useEffect(() => {
authStateRef.current = authState
})
return (
<Child authStateRef={authStateRef} />
)
// or, use Context to pass authStateRef.
}
Ah, outside component... I missed that, so it's like this: let globalAuthState
const Component = () => {
const authState = useAtom(authAtom) // or useState(...)
useEffect(() => {
globalAuthState = authState
})
return ...
} But, as you may notice, this naive pattern doesn't seem like good practice. |
So that mean, we cannot seperate buisness logic with the component right? |
You could make a custom hook, but it depends on React. If that's what you mean, that's correct. |
If you want a jotai-like decoupling from React, you might want to read this article: https://bennetthardwick.com/blog/recoil-js-clone-from-scratch-in-100-lines/ |
While I was ideating the persistence pattern #4 (comment), I came up with this idea. const callbackAtom = atom(null, (get, set, action) => {
action.callback(get(action.atom))
})
const [, getAtom] = useAtom(callbackAtom)
getAtom({
atom: anAtom,
callback: (value) => { console.log(value) /* or whatever */ },
}) It will only allow to read committed state, so it's essentially the same as: useEffect(() => {
globalAuthState = authState
}) in #60 (comment). Just found https://recoiljs.org/docs/api-reference/core/useRecoilCallback is a bit similar, or not. @tushar-upadhyay Would you tell us your use case? Maybe we can create a custom atom and/or custom hook. |
I use below in recoil
I'm using recoil for form state, the listener is inside the components inside the form component, and in this save form function, I can get the value of the form state without needed to listen for form state all the time in the form component - it makes a lot of different in my case Can we got something like this ? Thanks |
@x4080 Here's what I come up with for your use case. const saveFormAtom = atom(null, (get, set, [args, callback]) => {
// get, set...
const result = ...
callback(result)
})
const [, doSaveForm] = useAtom(saveFormAtom)
const saveForm = (args) => new Promise((resolve) => {
doSaveForm([args, resolve])
})
const result = await saveForm(...) |
@dai-shi Thanks again, the useRecoilCallback create a function that can get the latest value of the atom, without having to userecoil listener, the benefit is theres no rerender at all to get the value Sorry if im not clear, if we can get the value stored by jotai without actively listening to it (listener is in other component) then it will be perfect |
oh i just remember, the atomform content is the field contents of the form which is listened in other component for editing the fields |
So, we want a way to read the latest value without using it. So again, it's like this: const callbackAtom = atom(null, (get, _set, callback) => {
const result = get(...)
callback(result)
})
const [, cb] = useAtom(callbackAtom)
const callback = () => new Promise(cb) Are we on the same page? Maybe you want to show us a small working (non-working) example. |
im on mobile right now, ill create some thing to test later thanks |
@dai-shi I got it to work now, using your example
My implementation of save form look like this
Maybe the callbackAtom shoud be added to utility too ? It is useful tool Thanks for everything |
Yes, it'd be nice to add something in utils, because the impl is not very obvious.
|
Here's a draft: const useAtomCallback = <Arg, Result>(
callback: (get: Getter, set: Setter, arg: Arg) => Result
): (arg: Arg) => Promise<Result> => {
const anAtom = useMemo(() => atom(
null,
(get, set, [arg, resolve, reject]) => {
try {
resolve(callback(get, set, arg))
} catch (e) {
reject(e)
}
}
), [callback])
const [, invoke] = useAtom(anAtom)
return useCallback((arg) => new Promise((resolve, reject) => {
invoke([arg, resolve, reject])
}), [invoke])
} Is anyone interested in making this real?? |
Yes, read multiple atom at once is pretty important |
@x4080 Would you try |
@dai-shi Sorry for late reply, I'm not using typescript, so in plain javascript your function would be
Is that correct ? And how do I use it using my example above ?
And can it get multiple atom @once ? Thanks |
The JS version would be: const useAtomCallback = (callback) => {
const anAtom = useMemo(() => atom(
null,
(get, set, [arg, resolve, reject]) => {
try {
resolve(callback(get, set, arg))
} catch (e) {
reject(e)
}
}
), [callback])
const [, invoke] = useAtom(anAtom)
return useCallback((arg) => new Promise((resolve, reject) => {
invoke([arg, resolve, reject])
}), [invoke])
} You would use it like this: // in component
const saveForm = useAtomCallback(useCallback((get) => {
return get(atomForm) + get(anotherAtom)
}), []))
const result = await saveForm() |
@dai-shi Yes it works perfectly thanks |
@x4080 Thanks for confirming! Is anyone interested in drafting a PR for this new |
Well, I'm working on it now. |
Suppose i am storing some authentication state of a user in an atom and i want to call an API with that state. So how can i do that outside the functional component?
The text was updated successfully, but these errors were encountered: