Skip to content

Commit c2faff3

Browse files
committed
feat: add atomTree utility
- createAtom - createAtom.remove - createAtom.getSubTree - createAtom.getNodePath
1 parent 1431682 commit c2faff3

File tree

4 files changed

+2262
-2350
lines changed

4 files changed

+2262
-2350
lines changed

README.md

+110
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,113 @@ const todoFamily = atomFamily(
109109
### Codesandbox
110110

111111
<CodeSandbox id="huxd4i" />
112+
113+
---
114+
115+
# atomTree
116+
117+
[atomTree](https://github.com/jotaijs/jotai-family/blob/main/src/atomTree.ts) is a tree structure that allows you to create and remove atoms at a given path.
118+
119+
Use `atomTree` when you need a hierarchical way to store atoms, particularly if you expect many potential paths and want to reuse the same atom for repeated paths while also having an easy cleanup mechanism for subtrees.
120+
121+
```js
122+
import { atom } from 'jotai'
123+
import { atomTree } from 'jotai-family'
124+
125+
const tree = atomTree((path) => atom(path.join('-')))
126+
127+
const atomA = tree(['foo', 'bar'])
128+
const atomB = tree(['foo', 'bar'])
129+
130+
// Remove the atom at the given path
131+
tree.remove(['foo', 'bar'])
132+
```
133+
134+
## atomTree
135+
136+
The **atomTree** utility provides a hierarchical way to create, reuse, and remove Jotai atoms. Each atom is associated with a unique path, which is an array of unknown types. When you request the same path multiple times, `atomTree` ensures that the same atom instance is returned. You can also remove a specific atom or an entire subtree of atoms when they are no longer needed.
137+
138+
Use `atomTree` when you anticipate a large number of potential paths and want to:
139+
140+
- **Reuse the same atom** for repeated paths.
141+
- **Clean up** unwanted atoms easily, including entire subtrees.
142+
143+
```js
144+
import { atom } from 'jotai'
145+
import { atomTree } from 'jotai-family'
146+
147+
// Create a tree instance, passing a factory function
148+
// that takes a path array and returns a new atom.
149+
const tree = atomTree((path) => atom(path.join('-')))
150+
151+
// Create or retrieve the atom at ['foo', 'bar']
152+
const atomA = tree(['foo', 'bar'])
153+
const atomB = tree(['foo', 'bar'])
154+
155+
// atomA and atomB are the same instance.
156+
console.log(atomA === atomB) // true
157+
158+
// Remove the atom at ['foo', 'bar']
159+
// (and optionally remove its entire subtree)
160+
tree.remove(['foo', 'bar'])
161+
```
162+
163+
### API
164+
165+
#### Creating the tree
166+
167+
Creates a new hierarchical tree of Jotai atoms. It accepts a **factory** function that receives a path array and returns an atom.
168+
169+
```ts
170+
type Path = string[] // Or any other array type
171+
type AtomType = Atom<unknown>
172+
173+
function atomTree<Path, AtomType>(
174+
initializePathAtom: (path: Path) => AtomType
175+
): {
176+
(path: Path): AtomType
177+
remove(path: Path, removeSubTree?: boolean): void
178+
getSubTree(path: Path): Node<AtomType> | undefined
179+
getNodePath(path: Path): Node<AtomType>[]
180+
}
181+
```
182+
183+
- **`initializePathAtom`**: A function invoked whenever the tree needs to create a new atom. Receives the `path` as an argument and must return a Jotai atom.
184+
185+
The returned function has four main operations:
186+
187+
1. **`tree(path: Path): AtomType`**
188+
Creates (or retrieves) an atom at the specified path. Subsequent calls with the same path return the same atom instance.
189+
190+
2. **`tree.remove(path: Path, removeSubTree = false): void`**
191+
Removes the atom at the specified path. If `removeSubTree` is `true`, all child paths under that path are also removed.
192+
193+
3. **`tree.getSubTree(path: Path): Node<AtomType> | undefined`**
194+
Retrieves the internal node representing the specified path. This is useful for inspecting the tree structure. The node structure is as follows:
195+
196+
```ts
197+
type Node<AtomType> = {
198+
atom?: AtomType
199+
children?: Map<PathSegment, Node<AtomType>>
200+
}
201+
```
202+
203+
4. **`tree.getNodePath(path: Path): Node<AtomType>[]`**
204+
Returns an array of node objects from the root node to the node at the specified path, inclusive.
205+
206+
## Usage Example
207+
208+
```js
209+
import { atom } from 'jotai'
210+
import { atomTree } from 'jotai-family'
211+
212+
const btree = atomTree((path) => atom(`Data for path: ${path}`))
213+
214+
// Create or retrieve the atom at [true, false]
215+
const userAtom = btree([true, false])
216+
217+
console.log(store.get(userAtom)) // 'Data for path: true,false'
218+
219+
// Remove the atom (and optionally remove its subtree)
220+
btree.remove([true,false])
221+
```

0 commit comments

Comments
 (0)