我有一个文档对象,在可组合项中通过
id
进行管理,同时向外部显示 computed
(派生,只读)状态:
const state = reactive({})
export const useDocs = () => {
return {
create: doc => { state[doc.id] = doc },
read: computed(() => Object.values(state)),
update: (id, val) => {
Object.assign(state[id], val)
},
delete: (id) => { delete state[id] },
}
}
但是,如果没有
显式刷新,我无法让
computed
重新运行,我想避免这种情况,因为我认为必须有一个有效的全响应式解决方案。
const { create, read } = useDocs()
watch(() => read, docs => {
console.debug('change detected') // runs only initially
})
// ... later
create({ id: 1, foo: 'bar' }) // not reflected in watcher
我还想避免任何引用以使其可跨模板组合。
出现此问题是因为 Vue 的反应性系统无法自动跟踪普通反应性对象上的属性添加/删除。您可以在这里阅读 moare 的相关内容:
https://vuejs.org/guide/essentials/reactivity-fundamentals.html#limitations-of-reactive
https://vuejs.org/api/reactivity-core.html#reactive
https://codepen.io/mvsde/pen/abNOKOB
https://www.w3schools.com/jsref/jsref_map_new.asp
我的方法是使用 Map 而不是普通对象 - Map 的方法(如
set()
和 delete()
)由 Vue 的反应性系统跟踪,使每个文档在存储时具有反应性,并使用 Array.from(state.values())
来从地图正确导出
import { reactive, computed } from 'vue'
export const useDocs = () => {
// Using Map instead of plain object for better reactivity
const state = reactive(new Map())
return {
create: (doc) => {
state.set(doc.id, reactive(doc))
},
read: computed(() => Array.from(state.values())),
update: (id, val) => {
const doc = state.get(id)
if (doc) {
Object.assign(doc, val)
}
},
delete: (id) => {
state.delete(id)
},
// Optional: Get single document
getDoc: (id) => computed(() => state.get(id))
}
}