Vue组件Prop已传递但未更新:updateAll函数数据更新浏览器不渲染
Vue视图不更新问题:updateAll函数修改数据后浏览器未同步显示
问题描述
我编写了updateAll(data.items)函数,用于为数组元素随机分配新名称。通过Vue DevTools可以确认data.items已更新,且数据已传递给子组件,但浏览器视图并未同步更新。另外我编写了buildData.js工具文件,为兼容Vue和React项目做了通用性处理。
问题原因与解决方案
核心原因
问题大概率出在子组件Item.vue未正确响应meal属性的变化,或者v-for与v-if同用导致的渲染逻辑异常。
解决步骤
修正子组件的响应式引用
如果Item.vue中直接解构了props.meal的属性到非响应式变量(比如const { name } = props.meal),会导致属性变化无法被Vue追踪。解决方式:- 直接在模板中使用
{{ meal.name }},让Vue自动追踪属性变化; - 或者用
toRefs将props转为响应式引用:<script setup> import { toRefs } from 'vue' const props = defineProps({ meal: { type: Object, required: true } }) const { meal } = toRefs(props) </script>
- 直接在模板中使用
分离
v-for与v-if
原代码中将v-if="items.length > 0"放在v-for的Item元素上,会导致Vue每次渲染都要判断每个元素,影响更新逻辑。建议将判断移到父级模板:<template> <div class='items-container w-full md:w-max bg-gray-800 dark:bg-gray-800 text-white dark:text-black mx-auto mt-12 p-4 space-y-4'> <template v-if="items.length > 0"> <Item v-for="item in items" :key="item.id" :meal="item"/> </template> <p v-else class='text-white'>No items to display</p> </div> </template>确认
updateAll的逻辑正确性
你的updateAll函数通过map返回新数组,每个元素用扩展运算符创建新对象,这符合Vue响应式要求(替换数组会触发视图更新),这部分无需修改。
相关代码
HomeView.vue
<script setup> import { reactive, watch } from "vue"; import Hero from '@/components/Hero.vue' import FunctionButton from '@/components/FunctionButton.vue' import ItemsContainer from '@/components/ItemContainer.vue'; import * as dataFunc from '@/data/buildData' const data = reactive({ items: JSON.parse(localStorage.getItem('items')) || [] }) console.log(data.items) watch(() => data.items,(newValue) => { localStorage.setItem('items', JSON.stringify(newValue)) }, {deep: true}); </script> <template> <div class='w-2/3 mx-auto text-center'> <Hero HeroText="The one stop shop to store recipes!" /> <main> <h1 class="text-5xl font-extrabold dark:text-white">Recipe Manager</h1> <div class='functions gap-4 grid grid-cols-2 md:grid-cols-3 mt-8 mx-auto w-fit'> <FunctionButton name="Add new recipe" @click="() => data.items = [...data.items,...dataFunc.buildData(1)]"/> <FunctionButton name="Add 100 recipes" @click="() => data.items = [...data.items,...dataFunc.buildData(100)]"/> <FunctionButton name="Add 1000 recipes" @click="() => data.items = [...data.items,...dataFunc.buildData(1000)]"/> <FunctionButton name="Delete all recipes" @click="() => data.items = dataFunc.deleteAll()"/> <FunctionButton name="Edit all recipes" @click="() => data.items = dataFunc.updateAll(data.items)"/> </div> <ItemsContainer :items="data.items"/> </main> </div> </template>
ItemContainer.vue
<script setup> import Item from '@/components/Item.vue'; const props = defineProps({ items: {type: Array, default: () => []}, }) </script> <template> <div class='items-container w-full md:w-max bg-gray-800 dark:bg-gray-800 text-white dark:text-black mx-auto mt-12 p-4 space-y-4'> <Item v-for="item in items" v-if="items.length > 0" :key="item.id" :meal="item" /> <p v-else class='text-white'>No items to display</p> </div> </template>
buildData.js
import { v4 as uuidv4 } from 'uuid'; function create(){ const data = { id: uuidv4(), category: category[random(category.length)], name: meals[random(meals.length)], prepTime: randomTime(), cookTime: randomTime(), isFav: false } return data } function random(max){ return Math.round(Math.random() * 1000) % max; } const meals = [ "Roast Chicken", "Omelette", "Steak Pie", "Beef Stir Fry", "Fish And Chips", "Tomato And Prawn Risotto", "Pepperoni Pizza", "Cheesy Nachos", "Fajitas", "Baked Potato", "Full English Breakfast", "Pancakes", "Chocolate Brownies", "Meatballs With Red Pepper Sauce", "Chicken Cesar Salad", "Beef Burger", "Chips","Macaroni Cheese", "Fillet Steak", "Chicken Wings", "BBQ Ribs", "Tomato Soup", "Prawn Dim Sum", "Pork Gyozas", "Tomato Bruschetta", "Spring Rolls", "Beef Jerky", "Lasagne", "Spagetti Carbonara", "Salmon And Potatoes" ] const category = [ "Breakfast", "Lunch", "Dinner" ] function randomTime(){ return Math.round(Math.random() * 30) } function buildData(count){ const data = new Array(count); for(let i = 0; i<count; i++){ data[i] = create(); } return data; } function updateAll(currentArray){ return currentArray.map((item) => { return{...item, name: meals[random(meals.length)], } }) } function updateOne(item){ return{...item, name: meals[random(meals.length)], } } function favouriteAll(currentArray = []){ return currentArray.map((item) => { return {...item, isFav: true} }) } function deleteAll(){ const data = [] return data; } export {buildData, deleteAll, favouriteAll, updateAll, updateOne};
内容的提问来源于stack exchange,提问作者Aldo
相关产品推荐
相关产品推荐

