| name | item.js |
| description | Use this skill whenever the user works with item.js — a reactive state library based on a tree of Item nodes with signals, effects, and proxy support. Trigger for: creating/reading/ writing Items, using effect(), proxy traps, async/promise state, event handling, custom subclasses, or debugging reactive code built with this library.
|
item.js
import { item, effect, $item } from 'https://cdn.jsdelivr.net/gh/nuxodin/item.js@main/item.js'
Item
i = item()
i = item(42)
i = item({ a: 1, b: { b1: 2 } })
i.value
i.value = 99
i.get()
i.set(99)
i.patch({ a: 2 })
i.filled
i = item({ a: 1, b: 2 })
i.value = { b: 3 }
i.patch({ b: 3 })
i = item(NaN); i.value = NaN
i = item(0); i.value = -0
i.item('key')
i.has('key');
i.has('key')?.remove();
subsub = i.has('sub', 'subsub')
i.keys
i.items()
b = i.sub('a', 'b')
b.key
b.parent
b.path
b.remove()
b.root
for (const child of i) { }
JSON.stringify(i)
`${i}`
+i
## effect()
```js
const dispose = effect(() => {// runs immediately
count.value // .get() / .value / .has() / .keys register as dep
})
count.value = 1; // no effect
count.value = 2; // effect runs after batched microtask
dispose()
Proxy
p = i.proxy
p()
p(42)
p(1, 2)
'p:' + p
`p:${p}`
++p;
p.xyz
p.xyz = v
p.then
delete p.xyz
'xyz' in p
Object.keys(p)
{ ...p }
Object.assign(p, src)
p[$item]
for (const c of p) { }
for await (const c of p) { }
await p;
JSON.stringify(p())
Events
i.addEventListener('set', e => e)
i.addEventListener('change', e => e)
root.addEventListener('changeIn', e => e.target.path)
Custom Subclass
class MyItem extends Item {
static ChildClass = MyItemChild
}
Gotchas
i.addEventListener('set', () => i.value = x)
Async I/O (reader / writer / io)
i.reader = () => fetch('/api/value').then(r => r.json());
i.writer = v => fetch('/api/value', {method:'PUT', body: JSON.stringify(v)});
await i.read();
i.set(99);
await i.set(99);
await i.patch({a:3});
i.io.options.ttl = 10000;
i.io.options.optimistic = false;
i.io.options.debounceMs = 5;
i.io.setLocal(value);
class MyItem extends Item {
reader() { return fetch('/api/'+this.key).then(r => r.json()); }
writer(v) { return fetch('/api/'+this.key, {method:'PUT', body: JSON.stringify(v)}); }
static ChildClass = false;
}
Extensions
- Tools — HTTP Router, WebSocket, Change Tracking, JSON Sync, Schema Tools
- Adapters — Filesystem (Deno), Cookies, Storage (localStorage/sessionStorage), HTTP Client, WebSocket Client
Common Pitfalls
Don't read object values directly
const i = item({ a: 2 })
i.value.a
i.item('a').value
item() creates structure immediately (autovivification)
i.item('a').item('x')
i.has('a')?.item('x')
has() returns the Item, not a Boolean
if (i.has('sub')) { }
i.has('sub') === true
i.has('sub')?.value