Deprecated: atomFamily is deprecated and will be removed in v3. Please use the jotai-family package instead.Migration:// Before
import { atomFamily } from 'jotai/utils'
// After
import { atomFamily } from 'jotai-family'
atomFamily creates a family of atoms where each atom is memoized based on a parameter. This is useful for creating dynamic collections of atoms.
Signature
function atomFamily<Param, AtomType extends Atom<unknown>>(
initializeAtom: (param: Param) => AtomType,
areEqual?: (a: Param, b: Param) => boolean
): AtomFamily<Param, AtomType>
interface AtomFamily<Param, AtomType> {
(param: Param): AtomType
getParams(): Iterable<Param>
remove(param: Param): void
setShouldRemove(shouldRemove: ShouldRemove<Param> | null): void
unstable_listen(callback: Callback<Param, AtomType>): Cleanup
}
initializeAtom
(param: Param) => AtomType
required
Function that creates an atom for the given parameter
areEqual
(a: Param, b: Param) => boolean
Custom equality function for comparing parameters. Defaults to reference equality
Usage
Basic atom family
import { atomFamily } from 'jotai/utils'
import { atom } from 'jotai'
// Create a family of atoms for todo items
const todoAtomFamily = atomFamily((id: number) =>
atom({ id, title: '', completed: false })
)
function TodoItem({ id }: { id: number }) {
const [todo, setTodo] = useAtom(todoAtomFamily(id))
return (
<div>
<input
value={todo.title}
onChange={(e) => setTodo({ ...todo, title: e.target.value })}
/>
<input
type="checkbox"
checked={todo.completed}
onChange={(e) => setTodo({ ...todo, completed: e.target.checked })}
/>
</div>
)
}
With custom equality
import { atomFamily } from 'jotai/utils'
import { atom } from 'jotai'
interface TodoParam {
id: number
category: string
}
const todoFamily = atomFamily(
(param: TodoParam) => atom({ ...param, title: '' }),
(a, b) => a.id === b.id && a.category === b.category
)
const todoAtom = todoFamily({ id: 1, category: 'work' })
Removing atoms from family
import { atomFamily } from 'jotai/utils'
import { atom } from 'jotai'
const todoFamily = atomFamily((id: number) =>
atom({ id, title: '' })
)
function TodoList() {
const handleDelete = (id: number) => {
// Remove the atom from the family to free memory
todoFamily.remove(id)
}
return (
<div>
{/* ... */}
</div>
)
}
Auto-cleanup with setShouldRemove
import { atomFamily } from 'jotai/utils'
import { atom } from 'jotai'
const todoFamily = atomFamily((id: number) =>
atom({ id, title: '' })
)
// Remove atoms that were created more than 5 minutes ago
todoFamily.setShouldRemove((createdAt, param) => {
return Date.now() - createdAt > 5 * 60 * 1000
})
// To stop auto-cleanup
todoFamily.setShouldRemove(null)
Iterating over parameters
import { atomFamily } from 'jotai/utils'
import { atom } from 'jotai'
const todoFamily = atomFamily((id: number) =>
atom({ id, title: '' })
)
function TodoList() {
const params = Array.from(todoFamily.getParams())
return (
<div>
{params.map(id => (
<TodoItem key={id} id={id} />
))}
</div>
)
}
Methods
atomFamily(param)
Returns the memoized atom for the given parameter. If an atom doesn’t exist, it creates one.
getParams()
Returns an iterable of all parameters that have atoms created.
remove(param)
Removes the atom associated with the parameter from the family.
setShouldRemove(shouldRemove)
Sets a function that determines whether atoms should be automatically removed. The function receives:
createdAt: timestamp (in milliseconds) when the atom was created
param: the parameter of the atom
Returns true to remove the atom.
unstable_listen(callback)
This API is for advanced use cases and can change without notice.
Listens to atom creation and removal events. Returns a cleanup function.
const cleanup = todoFamily.unstable_listen(({ type, param, atom }) => {
console.log(`Atom ${type === 'CREATE' ? 'created' : 'removed'} for param:`, param)
})
// Stop listening
cleanup()
Migration to jotai-family
To migrate to the new jotai-family package:
- Install the package:
- Update imports:
// Before
import { atomFamily } from 'jotai/utils'
// After
import { atomFamily } from 'jotai-family'
The API remains the same.