造成该问题的原因
场景:父组件发送一个请求向服务器请求数据,但是子组件并不能及时的接收到该数据。
需求:子组件需要该数据进行页面的渲染,并且子组件需要通过该数据生成其他的数据进行相应的操作。
解决方法
1、使用v-if
当父组件中拿到了需要的数据就把条件设置为true
App.vue
<script setup>
const goods = ref({})
let flag = ref(false)
const getGoods = async () => {
const res = await axios.get('http://pcapi-xiaotuxian-front-devtest.itheima.net/goods?id=1369155859933827074')
goods.value = res.data.result
flag.value = true
}
getGoods()
<script>
<template>
<Sku v-if="flag" :goods="goods"/>
</template>
2、子组件中使用watch
Sku.vue
watch(() => props.goods.specs, () => {
pathMap = generatedPathDictionary();// 该函数中的数据会依赖到goods
initDisabledState(props.goods.specs, pathMap) // 初始化每个标签的禁用状态
}, {deep: true})
该方式要开启深度监听:因为我们监听的是一个对象,只有该对象被替换时才会被监听到,所以开启深度监听,并且需要立即执行。一般情况下这种方式比使用 v-if,子组件渲染的较快。
但是在我目前正在做的项目中不适用于该种方式,因为当我为goods种添加一个属性值 disabled 时触发某一个事件 会再次改变 该属性值,此时又会触发 watch 会重新刷新disabled的值。
但是可以通过一个判断语句只执行一个watch里面的回调就可以实现了。例如:
Sku.vue
let isWatch = true
watch(() => props.goods, () => { // 该监听器只执行以此即可
if(isWatch ) {
console.log(props.goods.specs);
pathMap = generatedPathDictionary();
initDisabledState(props.goods.specs, pathMap)
isWatch = false
}
}, {deep: true})
该种方式不仅可以实现功能,还能够提高性能,因为我们只需要拿到父组件传来的值即可,并不需要持续监听该值。
3、使用watchEffect
需要注意该监听器默认会立即执行,当数据为空的时候不要执行相应操作,否则会报错,加一个判断即可。
Sku.vue
watchEffect(() => {
pathMap = props.goods.specs && generatedPathDictionary();
props.goods.specs && initDisabledState(props.goods.specs, pathMap)
})