Question: how best to manage atom families?
See original GitHub issueScenario 1, forms with lots of fields: I have this common problem where I have a form with lots of fields. At first I think an Atom Family fills this need. I’ll set each atom in the family to one of the key value pairs of my form. But in order for that to work, I need to also have an atom that tracks all the keys in the form–otherwise how do I know what all my fields are? (There’s no way to get all the values out of a family.) That’s fine I guess, but it feels kinda clunky having two pieces of state that represent the same thing and need to be kept in sync. The reason I want to use an atom family in the first place is that when I update one value in my form, I don’t want all the form elements to update–only the one that updated should re-render. I also want there to be an easy way to get the form back as a single object so I’ve tried using selectors to combine the atom that has all the keys with the atom family, but I have to be careful not to use that selector higher up in the component hierarchy or else the entire tree will re-render when the selector reevaluates when any of the atoms update.
Question: What’s the best way to manage the keys in the form? Or just, what’s the best way to manage a form in general? Is having a companion atom with an array of its keys the best solution?
Scenario 2, asynchronously adding/removing from a family:
Another (similar) problem I have is a game where players can join a lobby. I want to store all the player objects in an atom family, keyed by their id. I thought atom effects would be perfect and I could subscribe each atom to websocket updates for its own player object, but the problem I’ve run into is… how do new atoms get added to the family? I receive a websocket message saying a player joined, but I can’t do a useRecoilState(playerState(newPlayer.id))
inside of that handler for the new atom because of the rules of hooks. And I don’t believe atom effects will solve my problem because (as far as I know) you can’t use them to add members to a family. How am I supposed to do this?
One (very bad) idea I had was to store the new player data from the websocket handler into local component state, then make a child component that accepts the new player object as a prop and then accesses its own atom from the family with a hook, but that feels super jank. I’d have something like:
function ComponentWhoseOnlyPurposeIsCreatingAnAtom({newPlayer}) {
const [player, setPlayer] = useRecoilState(playerFamily(newPlayer.id));
useEffect(() => {
setPlayer(newPlayer);
}, [newPlayer]);
return null; // don't render anything?
}
Then at that point, I have a similar solution to the form example where I have an atom that stores all the player IDs (the keys for its counterpart family of players), and I just add the new ID to that. This solution feels ridiculous and hacky, but I do think it would probably work eventually.
Question: How do I add new members to a family one at a time? Feels weird to have to put something in local state first, so it can go into a prop, so it can be used with a hook. In the form example I at least know all the fields I’ll have ahead of time. What about when it’s async?
I have a feeling that my trouble has to do with me not “thinking in Recoil” or something. Apologies if this is confusing.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:4
- Comments:8 (3 by maintainers)
Top GitHub Comments
What if I have a lof of players and is it still okay for me to manage a list of current players with just a single atom? Will there be any significant performance loss if the number of players is large?
You can store large structures in atoms. One significant factor when deciding the granularity of atoms is the granularity you want for subscriptions. If the actual user data is stored in a separate atom family, then changes in that would impact components for other users. If the set of users doesn’t change much, then it shouldn’t cause too many re-renders. But, if it does change a lot and a lot of components use that atom, then that could be a concern.