<script setup lang="ts" vapor>
-import { ref, shallowRef } from '@vue/vapor'
+import {
+ ref,
+ shallowRef,
+ triggerRef,
+ watch,
+ type ShallowRef,
+ type WatchSource,
+} from '@vue/vapor'
import { buildData } from './data'
import { defer, wrap } from './profiling'
const rows = shallowRef<
{
id: number
- label: string
+ label: ShallowRef<string>
}[]
>([])
-function setRows(update = rows.value.slice()) {
- rows.value = update
-}
-
+// Bench Add: https://jsbench.me/45lzxprzmu/1
const add = wrap('add', () => {
- rows.value = rows.value.concat(buildData(1000))
+ rows.value.push(...buildData(1000))
+ triggerRef(rows)
})
const remove = wrap('remove', (id: number) => {
rows.value.findIndex(d => d.id === id),
1,
)
- setRows()
+ triggerRef(rows)
})
const select = wrap('select', (id: number) => {
})
const run = wrap('run', () => {
- setRows(buildData())
+ rows.value = buildData()
selected.value = undefined
})
const update = wrap('update', () => {
const _rows = rows.value
- for (let i = 0; i < _rows.length; i += 10) {
- _rows[i].label += ' !!!'
+ for (let i = 0, len = _rows.length; i < len; i += 10) {
+ _rows[i].label.value += ' !!!'
}
- setRows()
})
const runLots = wrap('runLots', () => {
- setRows(buildData(10000))
+ rows.value = buildData(10000)
selected.value = undefined
})
const clear = wrap('clear', () => {
- setRows([])
+ rows.value = []
selected.value = undefined
})
const d998 = _rows[998]
_rows[1] = d998
_rows[998] = d1
- setRows()
+ triggerRef(rows)
}
})
await runLots()
}
}
+
+// Reduce the complexity of `selected` from O(n) to O(1).
+function createSelector(source: WatchSource) {
+ const cache: Record<keyof any, ShallowRef<boolean>> = {}
+ watch(source, (val, old) => {
+ if (old != undefined) cache[old]!.value = false
+ if (val != undefined) cache[val]!.value = true
+ })
+ return (id: keyof any) => (cache[id] ??= shallowRef(false)).value
+}
+
+const isSelected = createSelector(selected)
</script>
<template>
<tr
v-for="row of rows"
:key="row.id"
- :class="{ danger: row.id === selected }"
+ :class="{ danger: isSelected(row.id) }"
>
<td>{{ row.id }}</td>
<td>
- <a @click="select(row.id)">{{ row.label }}</a>
+ <a @click="select(row.id)">{{ row.label.value }}</a>
</td>
<td>
<button @click="remove(row.id)">x</button>
+import { shallowRef } from '@vue/vapor'
+
let ID = 1
function _random(max: number) {
for (let i = 0; i < count; i++)
data.push({
id: ID++,
- label:
+ label: shallowRef(
adjectives[_random(adjectives.length)] +
- ' ' +
- colours[_random(colours.length)] +
- ' ' +
- nouns[_random(nouns.length)],
+ ' ' +
+ colours[_random(colours.length)] +
+ ' ' +
+ nouns[_random(nouns.length)],
+ ),
})
return data
}