如何在 Vue3 中使用单个观察者观察 ref 和 reactive 对象
How to watch ref and reactive object with a single watcher in Vue3
Vue v3 docs 显示了一个通过将数组作为参数传递给单个观察者来观察多个引用的示例
我可以(以及如何)使用类似的方法通过单个观察者同时观察 ref
和 reactive
对象吗?
const state = reactive({
postPerPage: 10,
currentPage: 1,
});
const posts = ref([]);
const currentPosts = ref([]);
watch(
() => posts.value, // store value in currentPosts when the posts.value is updated (get data from api)
() => {
currentPosts.value = getCurrentPost();
}
)
watch(
() => {
return { ...state };
}
() => {
currentPosts.value = getCurrentPost();
}
)
docs 中的示例不是很清楚,但是当您将数组作为第一个参数传递(以查看多个源)时,该数组可以包含函数和裸引用的混合。请参阅下面的示例。
const app = Vue.createApp({
setup() {
const state = Vue.reactive({
postPerPage: 10,
currentPage: 1,
});
const posts = Vue.ref([]);
const normalRef = Vue.ref(0)
const watchCounter = Vue.ref(0)
Vue.watch([
//() => posts.value, // <-- this will not trigger watch callback on array push (only on array replace). Can be fixed by deep watch (uncomment last argument of watch)
//posts, // <-- same result as above
() => [ ...posts.value],
// () => state, // similar to array, this does not trigger on property change
() => ({ ...state }),
normalRef
],
(newValues, prevValues) => {
watchCounter.value++
console.log(`prev (${watchCounter.value}):`, prevValues);
console.log(`new (${watchCounter.value}):`, newValues);
},
// { deep: true }
)
return {
state,
posts,
normalRef,
watchCounter
}
},
mounted() {
const interval = 1000
setTimeout( () => this.state.currentPage = 2, interval)
setTimeout( () => this.posts.push({ a: 1 }), interval*2)
setTimeout( () => this.normalRef = 10, interval*3)
}
})
app.mount("#app")
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.11/vue.global.js" integrity="sha512-1gHWIGJfX0pBsPJHfyoAV4NiZ0wjjE1regXVSwglTejjna0/x/XG8tg+i3ZAsDtuci24LLxW8azhp1+VYE5daw==" crossorigin="anonymous"></script>
<div id="app">
<div>Watch counter {{ watchCounter }}</div>
<div>{{ state }}</div>
<div>{{ posts }}</div>
<div>{{ normalRef }}</div>
</div>
其他方法当然是继续使用两个观察者并将回调功能重构为单独的函数....
const callback = () => {
currentPosts.value = getCurrentPost();
}
watch(() => ({ ...state }), callback)
Vue v3 docs 显示了一个通过将数组作为参数传递给单个观察者来观察多个引用的示例
我可以(以及如何)使用类似的方法通过单个观察者同时观察 ref
和 reactive
对象吗?
const state = reactive({
postPerPage: 10,
currentPage: 1,
});
const posts = ref([]);
const currentPosts = ref([]);
watch(
() => posts.value, // store value in currentPosts when the posts.value is updated (get data from api)
() => {
currentPosts.value = getCurrentPost();
}
)
watch(
() => {
return { ...state };
}
() => {
currentPosts.value = getCurrentPost();
}
)
docs 中的示例不是很清楚,但是当您将数组作为第一个参数传递(以查看多个源)时,该数组可以包含函数和裸引用的混合。请参阅下面的示例。
const app = Vue.createApp({
setup() {
const state = Vue.reactive({
postPerPage: 10,
currentPage: 1,
});
const posts = Vue.ref([]);
const normalRef = Vue.ref(0)
const watchCounter = Vue.ref(0)
Vue.watch([
//() => posts.value, // <-- this will not trigger watch callback on array push (only on array replace). Can be fixed by deep watch (uncomment last argument of watch)
//posts, // <-- same result as above
() => [ ...posts.value],
// () => state, // similar to array, this does not trigger on property change
() => ({ ...state }),
normalRef
],
(newValues, prevValues) => {
watchCounter.value++
console.log(`prev (${watchCounter.value}):`, prevValues);
console.log(`new (${watchCounter.value}):`, newValues);
},
// { deep: true }
)
return {
state,
posts,
normalRef,
watchCounter
}
},
mounted() {
const interval = 1000
setTimeout( () => this.state.currentPage = 2, interval)
setTimeout( () => this.posts.push({ a: 1 }), interval*2)
setTimeout( () => this.normalRef = 10, interval*3)
}
})
app.mount("#app")
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.11/vue.global.js" integrity="sha512-1gHWIGJfX0pBsPJHfyoAV4NiZ0wjjE1regXVSwglTejjna0/x/XG8tg+i3ZAsDtuci24LLxW8azhp1+VYE5daw==" crossorigin="anonymous"></script>
<div id="app">
<div>Watch counter {{ watchCounter }}</div>
<div>{{ state }}</div>
<div>{{ posts }}</div>
<div>{{ normalRef }}</div>
</div>
其他方法当然是继续使用两个观察者并将回调功能重构为单独的函数....
const callback = () => {
currentPosts.value = getCurrentPost();
}
watch(() => ({ ...state }), callback)