Vue3中OrdersComponent组件未正常加载渲染问题排查
Vue组件渲染问题排查
问题复现代码
我编写了如下父组件代码:
<script setup> import {defineProps, ref, watch} from "vue"; import ProductsComponent from '@/components/Products.vue' import OrdersComponent from '@/components/Orders.vue' import {useTableOrderStore} from "@/store/tableOrder"; const tableOrderStore = useTableOrderStore() const props = defineProps({ orderID: { type: Number }, tableID: { type: Number }, tableName: { type: String } }) let orders = ref([]) watch(props, (newProp, oldProp) => { orders = tableOrderStore.tableOrders console.log(orders) }) </script> <template> <products-component :tableName="tableName"></products-component> <orders-component v-for="order in orders" :order="order" :key="order.id"></orders-component> </template>
该组件中引入加载的 OrdersComponent 子组件代码如下:
<script setup> import {watch} from "vue"; let props = defineProps({ order: { type: Array, required: true } }) watch(props, (newProp, oldProp) => { console.log(newProp) }) console.log(12333) </script> <template> <div class="row"> {{ order }} Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias, expedita? </div> </template>
问题现象
父组件页面展示时,ProductsComponent 可正常加载并显示,但 OrdersComponent 始终无法渲染。
代码错误说明
一共存在3个直接/间接导致子组件不渲染的问题:
- ref响应式变量赋值方式错误
父组件中orders是通过ref([])定义的响应式变量,在watch回调中直接写orders = tableOrderStore.tableOrders是错误写法:这种写法会直接把orders变量从ref实例替换为普通值,完全丢失响应式关联,模板中读取到的orders始终是初始定义的空数组,v-for遍历空数组自然不会生成任何子组件实例。正确赋值方式应该修改为orders.value = tableOrderStore.tableOrders。 - watch触发逻辑不合理
父组件中给orders赋值的逻辑写在了watch(props)的回调里,这个回调只有在props的属性发生变化时才会执行,且没有开启immediate: true配置。如果组件初始化时传入的props后续没有变动,这个回调根本不会触发,orders就会一直保持初始的空数组状态,完全拿不到store里的订单数据。 - 子组件Prop类型定义不匹配
父组件v-for遍历的是订单列表,传给子组件的order是单个订单对象,但子组件中给orderprop定义的类型是Array,类型校验不通过会抛出Vue警告,虽然不是导致不渲染的核心原因,但属于明确的代码错误,单个订单的类型应该定义为Object。
额外的代码规范问题
- 父子组件中直接监听整个
props对象的写法默认是浅监听,无法捕获props内部属性的深层变动,如果要监听props变化,建议明确指定要监听的具体属性,或者手动开启deep: true配置。 - 父组件中获取store订单数据的逻辑不需要放在watch props里,和props变动无关的逻辑可以直接在setup顶层执行,或者通过计算属性直接关联store中的响应式数据。
内容的提问来源于stack exchange,提问作者Sasha
相关产品推荐
相关产品推荐

