Shared Atoms
Check out this Counter component ↓
Counter
Here's (a simplified version of) the code ↓
import { Atom, useAtom } from '@effect-atom/atom-react'
const countAtom = Atom.make(0)
export function Counter() {
const [count, setCount] = useAtom(countAtom)
return (
<div>
<div>{count}</div>
<button onClick={() => setCount((c) => c + 1)}>
Increment
</button>
<button onClick={() => setCount((c) => c - 1)}>
Decrement
</button>
</div>
)
}
Now, let's see what happens if we have multiple counters on the same page.
import { Counter } from './Counter'
<div>
<Counter />
<Counter />
</div>
Counter
Counter
As you can see, the counters are not independent. This is because they're using the same countAtom.
The Solution: Atom.family
To create multiple independent counters, we need to use Atom.family. This allows us to create a set of identifiable atoms, ensuring we get a stable reference for each key.
import { Atom, useAtom } from '@effect-atom/atom-react'
// Create a family of counter atoms, each identified by a number.
const counterFamily = Atom.family((id: number) =>
Atom.make(0)
)
export function FamilyCounter({ id }: { id: number }) {
// Call the counterFamily with the id to get the atom
const [count, setCount] = useAtom(counterFamily(id))
return (
<div>
<h3>Counter #{id}</h3>
<div>{count}</div>
<button onClick={() => setCount((c) => c + 1)}>
Increment
</button>
<button onClick={() => setCount((c) => c - 1)}>
Decrement
</button>
</div>
)
}
Now when we render multiple counters with different IDs, they maintain independent state.
<div>
<FamilyCounter id={1} />
<FamilyCounter id={2} />
<FamilyCounter id={3} />
</div>
Counter #1
Counter #2
Counter #3
Now, just for fun, here's Counter 3 again! ↓
<FamilyCounter id={3} />
Counter #3
Calling the family function with the same ID will return the same atom.