Consider a reactive object (or array) that is dynamically populated with data:
import { reactive, computed } from 'vue'
const entries = reactive({}) // global state beyond Template level
const docs = [
{ id: 1, name: 'foo', value: 'bar' },
{ id: 2, name: 'bar', value: 'moo' }
]
Object.entries(docs).forEach(doc => {
entries[doc.id] = doc
})
export const useEntries = () => {
const getAll = computed(() => Object.values(entries))
const update = (id, newValue) => {
entries[id].value = newValue
}
const changes = () => { /* ??? */ }
return { getAll, update, changes }
}
For performance reason, I want a Templates to watch only updated entries and not iterate the entire list, if the update is triggered within another Template.
Template A:
<script setup>
import { useEntries } from '/path/to/useEntries'
const { update } = useEntries()
</script>
<template>
<button @click="update(1, 'moo)">Make moo</button>
</template>
Template B:
<script setup>
import { useEntries } from '/path/to/useEntries'
import { watch } from 'vue'
const { changes } = useEntries()
watch(changes, (entries) => {
// process only updated entries here
})
</script>
Note, in this example I update only one entry, but it also might be 50 at once in a list of hundreds. I'd like to avoid a second list to manage.
you can manage "delta" object that holds changes you store entry’s id in the changes object then add changes function that returns only entries that have been updated
import { reactive, computed } from 'vue'
const entries = reactive({})
const updatedEntries = reactive(new Set())
const docs = [
{ id: 1, name: 'foo', value: 'bar' },
{ id: 2, name: 'bar', value: 'moo' }
]
docs.forEach(doc => {
entries[doc.id] = doc
})
export const useEntries = () => {
const getAll = computed(() => Object.values(entries))
const update = (id, newValue) => {
entries[id].value = newValue
updatedEntries.add(id)
}
const changes = computed(() => {
const changed = {}
updatedEntries.forEach(id => {
changed[id] = entries[id]
})
return changed
})
return { getAll, update, changes }
}
Template A
<template>
<button @click="update(1, 'moo')">Make moo</button>
</template>
<script setup>
import { useEntries } from '/path/to/useEntries'
const { update } = useEntries()
</script>
Template B
<template>
<div v-for="entry in changedEntries" :key="entry.id">
{{ entry.name }}: {{ entry.value }}
</div>
</template>
<script setup>
import { useEntries } from '/path/to/useEntries'
import { watch, ref } from 'vue'
const { changes } = useEntries()
const changedEntries = ref({})
watch(changes, (newChanges) => {
changedEntries.value = newChanges
})
</script>