atomFamily
atomFamily<K, T>(defaultFactory?: (key: K) => T): AtomFamily<K, T>valdres Create a keyed collection of atoms
Creates a family of atoms keyed by a parameter. Useful for collections of entities like users, todos, or items where each instance needs its own piece of state.
Usage
import { atomFamily } from "valdres"
// Simple family with no default
const todoAtom = atomFamily()
store.set(todoAtom("abc-123"), { title: "Buy milk", done: false })
store.get(todoAtom("abc-123")) // { title: "Buy milk", done: false }
With a default value factory
Pass a function that receives the key and returns the default value:
const userAtom = atomFamily(id => ({
id,
name: "",
email: "",
}))
// The default is generated when first accessed
store.get(userAtom("user-1")) // { id: "user-1", name: "", email: "" }
Key identity
Family calls are keyed by a deterministic structural encoding. Primitive types,
argument count, Arrays, plain Objects, Dates, Maps, and Sets remain distinct;
object property order and Map/Set insertion order do not affect identity.
BigInt is supported too.
Values without deterministic structural semantics—such as Symbols, functions,
Promises, class instances, accessor properties, and cyclic structures—throw a
TypeError. Use keyOf to derive a supported identity for those arguments, or
to intentionally group multiple arguments:
type Entity = { id: string; self?: Entity }
const entityAtom = atomFamily<Entity, [Entity]>(entity => entity, {
keyOf: entity => entity.id,
})
keyOf receives the same argument tuple as the family factory. Its result is
run through the same canonical codec.
The legacy release(...args) method is deprecated and has no effect. Family
members leave the weak identity cache automatically once no caller or store can
reach them. Manual eviction could otherwise create two live member objects for
the same arguments and split their values across stores.
Subscribing to a family
store.sub(todoAtom, id => {
console.log("Changed todo ID:", id)
})
In React
import { useValue } from "valdres-react"
function UserProfile({ userId }) {
const user = useValue(userAtom(userId))
return <div>{user.name}</div>
}
See also
- atom — create a single atom
- selectorFamily — derive state from a family of atoms
- index — reactively filter family members by a term