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
writedirection (since v1.6.4), providing a simple way to modify the original atom with actions likeremove,insert, andmove.An optional
keyExtractorfunction 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
splitAtomis used within a React render loop, thekeyExtractormust be a stable function that maintains object equality (shallow equality). This requirement doesn't apply outside of render loops. - Providing a
keyExtractorenhances 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. keyExtractoris 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.