-
I'm curious about approaches for handling state that is discovered at runtime, like a user session: It is initially undefined, but for atoms that deal with displaying user details or making use of the user session, it is effectively required. Say there are several atoms that manage data synced to a local cache, which is fetched using an api client, that in turn depends on a user session. Is |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 11 replies
-
Hey @joprice. Normally, I'd say this isn't something you'd have to think about. Components lazily initialize atoms as they're mounted. You wouldn't typically render a I'm not sure I'm following this part:
Some (pseudo-)code would be helpful. But I'm imagining this basic setup for now: const userDataAtom = atom('userData', undefined) // populated later
const getUserName = ({ get }: AtomGetters) => get(userDataAtom)?.name
function UserName() {
const userName = useAtomSelector(getUserName)
return userName == null ? null : <span>{userName}</span>
} The pain point with this setup that I think you're pointing out here:
is having to deal with undefined. There are a few ways to go about it. Using an If you really are guaranteeing that the data is defined when it's used in certain places, then a wrapper atom like this would be my preferred approach: const loadedUserDataAtom = ion('loadedUserData', ({ get }) => {
const userData = get(userDataAtom)
if (!userData) {
throw new Error('tried accessing user data before it was loaded')
}
return userData
}) Now consumers of // TS knows there's no need for `?.`:
const getUserName = ({ get }: AtomGetters) => get(loadedUserDataAtom).name
function UserName() {
const userName = useAtomSelector(getUserName)
// and no need for `== null` check:
return <span>{userName}</span>
} There may be more approaches, but let me know if I'm going in the wrong direction here. |
Beta Was this translation helpful? Give feedback.
-
Yes that's exactly the situation I was thinking of. With other approaches to state that don't attempt to represent the graph statically, I'd have some sort of "AuthGate" that ensures the nullability is handled at runtime, then from there on out the data is accessed through a non-nullable variable stored in context. For a single value like auth, it's easy enough to add the runtime check you suggested, but if you have four or five dependencies that should all be in a certain state before using them, it becomes cumbersome and error-prone. Even with a single runtime dependency like in the auth example above, I had issues where logging out caused display of errors in components that assumed the user was non-nullable. (This could have been something subtle with contexts and react native navigation, but it's not something I've had happen since I switched to passing a non-nullable reference downward since the types rule out that case). What I'd like in general is to have a sub-graph of atoms to be "unlocked" by a "key", similar to a object-capabilities model or how subsets of a graphql schema require parameters to access. I'm now starting to see that context is the way to go since this is a runtime verification. Just trying to figure out what I should be taking care of and what Zedux should handle. I like Zedux since it has most everything baked in that you normally have to piece together with multiple libraries, and especially that the data layer is testable outside of the UI, so I was attempting to see if I could fit the full runtime state into the static graph. I think I'll try out an approach where the base atoms are parameterized, and then provided via |
Beta Was this translation helpful? Give feedback.
@joprice Cool! A few things:
injectEffect
shouldn't be necessary there, unless you specifically want to wait a tick