Reactive equivalent of array.map. Runs the callback only for entries
it hasn't rendered before — existing rows keep their state instead of
being recreated on every change, and removed rows are disposed. Powers
<For/> and works with arrays, Sets and Maps.
Plain array.map(item => <li>{item}</li>) can't react to mutations
without rebuilding every row from scratch, losing focus, DOM state,
and any work the row performed. map avoids that by keying rows by
identity and reusing them across updates.
| name | type | description |
|---|---|---|
list |
iterable | () => iterable |
array, Set, Map, or a signal returning one of those |
callback |
(item, index) => JSX.Element |
runs once per row; its return value is rendered |
noSort? |
boolean |
when true, reordering the input does not reorder the DOM |
fallback? |
JSX.Element |
rendered when the input is empty |
reactiveIndex? |
boolean |
when true, index is a signal accessor, not a number |
Returns: a function the renderer calls to produce the rendered rows.
Pass the reader function (items.read) so the list stays reactive.
Rows are keyed by item identity, so reordering the input reuses each
row's existing DOM node — only their order changes. When
reactiveIndex is true, the second callback argument is a reader
function whose value updates as rows move.
Reuses every row's DOM node on reorder — only their order changes.
import { map, render, signal } from 'pota'
function App() {
const items = signal(['apple', 'banana', 'cherry'])
return (
<div>
<button
on:click={() => items.update(list => [...list].reverse())}
>
reverse
</button>
<ul>
{map(items.read, item => (
<li>{item}</li>
))}
</ul>
</div>
)
}
render(App)
Push and shift rows; only the affected rows are created or removed, the rest keep their DOM.
import { map, render, signal } from 'pota'
function App() {
const items = signal([1, 2, 3])
let next = 4
return (
<div>
<button
on:click={() => items.update(list => [...list, next++])}
>
push
</button>
<button on:click={() => items.update(list => list.slice(1))}>
shift
</button>
<ul>
{map(items.read, item => (
<li>row {item}</li>
))}
</ul>
</div>
)
}
render(App)
The reactiveIndex flag turns index into a reader that updates as
rows move — reverse renumbers the existing rows in place — and
clear empties the list so the fallback renders.
import { map, render, signal } from 'pota'
function App() {
const items = signal(['a', 'b', 'c'])
return (
<div>
<button
on:click={() => items.update(list => [...list].reverse())}
>
reverse
</button>
<button on:click={() => items.write([])}>clear</button>
<ul>
{map(
items.read,
(item, index) => (
<li>
{index} — {item}
</li>
),
false,
<li>nothing here</li>,
true,
)}
</ul>
</div>
)
}
render(App)
map accepts any iterable; Maps iterate over their values.
import { map, render } from 'pota'
function App() {
return (
<div>
<ul>
{map([1, 2, 3], item => (
<li>{item}</li>
))}
</ul>
<ul>
{map(new Set([4, 5, 6]), item => (
<li>{item}</li>
))}
</ul>
<ul>
{map(new Map().set('a', 7).set('b', 8), item => (
<li>{item}</li>
))}
</ul>
</div>
)
}
render(App)