Discussion: atomFamily better alternative
See original GitHub issueI’ve tried to use atomFamily
or implement my own alternative. But looks like I had no succeess, so I decided to discuss my vision and ideas.
atomFamily drawback
As I understand atomFamily
was copied from RecoilJS. While at first glance it might look good, trying to implement this pattern in real life fails shortly. That’s the problems I found.
Can’t fetch or load data to atomFamily
Most often in real life before starting managing atoms
we need to fetch data from somewhere - from local database or server.
We don’t want to do multiple requests for each atom from atomFamily
. While our strategy is to do the least requests returning most data, these requests will be highly specialized.
For example I have sqlite tags
table
id | label | iconName | iconColor | isSelected |
---|---|---|---|---|
e8a63d19-ae64-44df-b3a8-0adbf7df1155 | Family | users | rgba(227, 95, 166, 1) | 1 |
7d3bfd19-3c88-4d12-8665-ddd405af5aee | Health | heartbeat | rgba(242, 108, 108, 1) | 0 |
6f07bc4e-79b1-44d2-b65e-460422ba137a | Home | home | rgba(89, 212, 220, 1) | 0 |
18efd821-9088-48a1-9bf7-2db589e69621 | Shopping | shopping-basket | rgba(114, 180, 31, 1) | 0 |
eb6a269b-66c7-4a6e-a588-ebff855800d1 | Friends | user-friends | rgba(236, 122, 86, 1) | 0 |
8d9d7cd1-12a9-4d60-90be-7c028bbcfc18 | Grooming | cut | rgba(217, 110, 117, 1) | 0 |
and I want to make one request to load data
const tagRepository = getTagRepository();
return tagRepository.find()
atomFamily
do not allow to do that
atomFamily requires separate atom to manage ids
atomFamily
requires to manage separate atom
with list of ids. But most entities from server or local database already have id
as part of its data.
- additional request to load ids is required
- separate atom with ids requires additonal coordination which complicates code
@Entity({ name: 'tags' })
export class Tag {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column('text')
label!: string;
...
}
atomFamily doesn’t give performance advantage
If we add new todo
to todoList
https://github.com/jacques-blom/recoil-todo-list/blob/ccbec84f3a438b8707f235263bf079fab4bbd987/src/components/Input.tsx#L31
const insertTask = useRecoilCallback(({set}) => {
return (label: string) => {
const newTaskId = tasks.length
set(tasksState, [...tasks, newTaskId])
set(taskState(newTaskId), {
label: label,
complete: false,
})
}
})
this updates tasksState
atom with ids.
export const tasksState = atom<number[]>({
key: 'tasks',
default: [],
})
const tasks = useRecoilValue(tasksState)
return (
<div>
{tasks.map((id) => (
<Task id={id} key={id} />
))}
</div>
)
so all <Task />
components will be rerendered again (but reconcilation - real DOM update - should happen only for updated task). I think there is no difference then just updating one big atom with list of todos.
The only advantage for atomFamily
is when we update one atom
- that should lead to updating only one component.
But atomFamily
doesn’t solve insert / delete
use-cases.
Also, if we have example with filtered todo-list
const filteredTasksAtom = atom(
get => {
const allTasks = get(allTasksAtom)
return allTasks.filter(<some condition>)
}
)
this is more like a toy example. We might not have all tasks in memory. In real code we will have to load filtered tasks from server / database using query.
const filteredTasksAtom = atom(
get => {
return fetch('/tasks?isCompleted=0&isTracked=1')
}
)
How to coordinate allTasksAtom
and filteredTasksAtom
because they might overlap?
Since fetch('/tasks?isCompleted=0&isTracked=1')
might return updated data we want to update existing atoms with this updated information from request, add new atoms and delete old ones. So we want to sync them.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:9 (6 by maintainers)
@dai-shi I’ve got some experience and it looks like it’s working. But I’m short on time. As soon as I will have more time I’ll fill in more information. Close for now.
I’ve switched to Recoil for my application. It has exactly the same requirements - filtered todo list.
I’m still investigating. But looks like I solved all problems (with hacks) and soon will share experience.