Split
splitAtom
The splitAtom
utility is designed for scenarios where you need to obtain an atom for each element in a list. It operates on read/write atoms containing a list, returning an atom that holds a list of atoms, each corresponding to an item in the original list.
Signature
A simplified type signature for splitAtom
would be:
type SplitAtom = <Item, Key>(arrayAtom: PrimitiveAtom<Array<Item>>,keyExtractor?: (item: Item) => Key): Atom<Array<PrimitiveAtom<Item>>>
Key Features
The returned atom contains a dispatch function in the
write
direction (since v1.6.4), providing a simple way to modify the original atom with actions likeremove
,insert
, andmove
.An optional
keyExtractor
function can be provided as a second argument to enhance stability and performance.
Key Extractor
The splitAtom
utility supports a second argument which is a key extractor function:
export function splitAtom<Item, Key>(arrAtom: WritableAtom<Item[], [Item[]], void> | Atom<Item[]>,keyExtractor?: (item: Item) => Key)
Important considerations for the keyExtractor
:
- If
splitAtom
is used within a React render loop, thekeyExtractor
must be a stable function that maintains object equality (shallow equality). This requirement doesn't apply outside of render loops. - Providing a
keyExtractor
enhances the stability of the atom output (which makes memoization hit cache more often). It prevents unnecessary subatom recreation due to index shifts in the source array. keyExtractor
is an optional optimization that should only be used if the extracted key is guaranteed unique for each item in the array.
Example Usage
Here's an example demonstrating the use of splitAtom
:
import { Provider, atom, useAtom, PrimitiveAtom } from 'jotai'import { splitAtom } from 'jotai/utils'import './styles.css'const initialState = [{task: 'help the town',done: false,},{task: 'feed the dragon',done: false,},]const todosAtom = atom(initialState)const todoAtomsAtom = splitAtom(todosAtom)type TodoType = (typeof initialState)[number]const TodoItem = ({todoAtom,remove,}: {todoAtom: PrimitiveAtom<TodoType>remove: () => void}) => {const [todo, setTodo] = useAtom(todoAtom)return (<div><inputvalue={todo.task}onChange={(e) => {setTodo((oldValue) => ({ ...oldValue, task: e.target.value }))}}/><inputtype="checkbox"checked={todo.done}onChange={() => {setTodo((oldValue) => ({ ...oldValue, done: !oldValue.done }))}}/><button onClick={remove}>remove</button></div>)}const TodoList = () => {const [todoAtoms, dispatch] = useAtom(todoAtomsAtom)return (<ul>{todoAtoms.map((todoAtom) => (<TodoItemtodoAtom={todoAtom}remove={() => dispatch({ type: 'remove', atom: todoAtom })}/>))}</ul>)}const App = () => (<Provider><TodoList /></Provider>)export default App
This example demonstrates how to use splitAtom
to manage a list of todo items, allowing individual manipulation of each item while maintaining the overall list atom.