Vue3执行函数后DOM不更新问题求助(点赞收藏功能)
Vue3 点赞/收藏功能UI不即时更新问题
我在Vue3中开发点赞/收藏功能时遇到问题:点击点赞或取消点赞后,前端UI不会即时更新,只有刷新页面才能显示最新状态。后端的点赞、取消点赞功能运行正常,以下是父组件和子组件代码,求解决DOM重新渲染的问题。
父组件代码
<template> <Suspense> <template #default> <div class="is-flex is-1 is-flex-wrap-wrap" v-if="reciepes"> <ReciepeCard class="card radius-small mx-2 my-3 p-3" v-for="(reciepe, i) in reciepes" :reciepe="reciepe" :key="i" :savedDishesId="savedReciepesIds" @openReciepe="openFunc(reciepe)" @likeIndi="isLiked(reciepe)" > </ReciepeCard> </div> </template> </Suspense> </template> <script setup> import ReciepeCard from '../components/reciepe-cards/reciepeCard.vue' const reciepeStore = useReciepeStore(), userStore = useUserStore(), loginStore = useLoginStore(), router = useRouter() const reciepes = ref([]), username = ref('User'), savedReciepesIds = ref([]) onMounted(async () => { fetchData() let userId = VueCookies.get('id') if (userId) { let user = await userStore.fetchAccDetails(VueCookies.get('id')) username.value = user.username } savedReciepesIds.value = await userStore.fetchSavedDishesId(userId) console.log(savedReciepesIds.value) }) async function isLiked(userId) { console.log("parent"); savedReciepesIds.value = await userStore.fetchSavedDishesId(userId) } async function fetchData() { reciepes.value = await reciepeStore.getReciepes() } console.log(loginStore.isAuth()) function openFunc(reciepe) { router.push({ path: `/reciepe/${reciepe._id}` }) } </script>
子组件代码
<template> <div class="reciepe-card bg-color-white" style="cursor: pointer"> <div class="card-head" @click="emits('openReciepe')"> <figure class=""> <img :src="props.reciepe.img" alt="Recipe Image" class="image radius-default" /> </figure> </div> <div class="card-desc" @click="emits('openReciepe')"> <h3 class="is-size-3 color-tx-sec">{{ props.reciepe.dish_name }}</h3> <p class="is-size-5">{{ resizeText(props.reciepe.description) + '...' }}</p> </div> <div class="is-flex is-justify-content-space-between is-align-items-center is- mt-3"> <p class="has-text-link" @click="emits('openReciepe')">View more</p> <Icon icon="ph:heart-bold" v-if="!isLiked" style="height: 2rem; width: 2rem" @click="toogleLike()" ></Icon> <Icon icon="mdi:heart" color="red" v-else style="height: 2rem; width: 2rem" @click="toogleLike()" ></Icon> </div> </div> </template> <script setup> import { Icon } from '@iconify/vue' import { computed, onMounted, ref, watch } from 'vue' import { useUserStore } from '../../stores/userStore' import VueCookies from 'vue-cookies' const isLiked = ref(false) onMounted(() => { updateLikeStats() }) watch( () => props.savedDishesId, () => { updateLikeStats() } ) // const isLiked = computed(() => { // if (props.savedDishesId != null || props.savedDishesId != undefined) // return !props.savedDishesId.includes(props.reciepe._id) // else return false // }) const userStore = useUserStore(), userId = ref(VueCookies.get('id') || null) const emits = defineEmits(['openReciepe', 'likeIndi']) const props = defineProps({ reciepe: { type: Object, required: true }, savedDishesId: { type: Array, required: true, default: () => [] } }) function resizeText(text) { return text.slice(0, 120) } async function toogleLike() { await userStore.toogleLikeReciepe(props.reciepe._id, { userId: userId.value }) emits('likeIndi',userId.value); updateLikeStats() } function updateLikeStats() { isLiked.value = props.savedDishesId.includes(props.reciepe._id) console.log(isLiked.value) } </script>
问题修复方案
1. 修正v-for的key值(父组件)
当前用数组索引i作为key,会导致Vue无法正确识别组件身份,改为用唯一的reciepe._id:
<ReciepeCard class="card radius-small mx-2 my-3 p-3" v-for="reciepe in reciepes" :reciepe="reciepe" :key="reciepe._id" <!-- 替换为唯一ID --> :savedDishesId="savedReciepesIds" @openReciepe="openFunc(reciepe)" @likeIndi="isLiked" <!-- 直接传函数即可,子组件emit的参数会自动接收 --> ></ReciepeCard>
2. 改用computed自动计算点赞状态(子组件)
去掉手动维护的isLiked ref和更新函数,用computed自动响应props变化:
// 删除以下代码: // const isLiked = ref(false) // onMounted(() => { updateLikeStats() }) // watch(() => props.savedDishesId, () => { updateLikeStats() }) // function updateLikeStats() { ... } // 替换为: const isLiked = computed(() => { return props.savedDishesId.includes(props.reciepe._id) })
这样只要父组件的savedReciepesIds更新,子组件的isLiked会自动同步,UI即时刷新。
3. 可选:优化数组监听(若坚持用ref)
如果不想用computed,需要给watch添加深度监听,因为数组是引用类型,浅监听无法检测内部元素变化:
watch( () => props.savedDishesId, () => { updateLikeStats() }, { deep: true } // 添加深度监听配置 )
内容的提问来源于stack exchange,提问作者Valor Hec07
相关产品推荐
相关产品推荐

