Vue.js 3 - 如果 props 带有父组件中的数组成员,则在子组件中观看 props 不起作用

Vue.js 3 - watching props in child component does not work if props comes with a member of array in parent component

我正在使用Vue.js 3.我遇到了问题,让我们先看看代码。

代码

ChildComponent.vue

<template>
<div>
  {{ modelValue }}
  <input v-model="resultString"/>
  <button @click="showModelValue">show model value</button>
</div>
</template>

<script lang="ts">
import {defineComponent, PropType, ref, watch} from "vue";

export default defineComponent({
  props: {
    modelValue: {
      type: Object as PropType<number>,
      required: true,
    }
  },
  emits:['update:modelValue'],
  setup(props) {
    const resultString = ref<string>("");
    watch(() => props.modelValue, (newVal:number, oldVal:number) => {
      if (newVal % 2 == 0) {
        resultString.value = 'even';
      } else {
        resultString.value = 'odd';
      }
    }, {deep: true});
    const showModelValue = () => {
      console.log(props.modelValue);
    }
    return { resultString, showModelValue }
  }
})
</script>

<style scoped>

</style>

ParentComponent.vue

<template>
  <div class="main-container">
    <child-component v-model="test1" />
    <button @click="increaseTest1">increase test1</button>

    <hr/>
    Cannot use v-model within v-for!
    <!--
    <div v-for="(testNum, index) in test2">
      <child-component v-model="testNum" /> <button @click="increaseTest2(index)">increase test2</button>
    </div>
    -->
    <hr/>

    <div v-for="(testNumWrapper, index) in test3">
      <child-component v-model="testNumWrapper.val" /> <button @click="increaseTest3(index)">increase test3</button>
    </div>
  </div>
</template>

<script lang="ts">
import {defineComponent, onMounted, ref} from "vue";
import ChildComponent from "@/main/components/pc/ChildComponent.vue";
export default defineComponent({
  components: {ChildComponent},
  setup() {
    const test1 = ref<number>(1);
    const increaseTest1 = () => test1.value++;

    /*
    const test2 = ref<number[]>([3,1,4,1,5,9]);
    const increaseTest2 = (index:number) => test2.value[index]++;
    const updateTest2 = (e:any) => {
      console.log(e);
    };
    */

    const test3 = ref<{val:number}[]>([]);
    const increaseTest3 = (index:number) => test3.value[index].val++;

    onMounted(() => {
      // This triggers watch() in childComponent.
      test1.value = 4;

      // But these do NOT trigger watch() in childComponent.
      test3.value = [{val: 3},{val: 1},{val: 4},{val: 1},{val: 5},{val: 9}];
    });

    return {
      test1, increaseTest1,
      //test2, increaseTest2, updateTest2,
      test3, increaseTest3,
    }
  }
});
</script>

<style scoped>

</style>

以上代码是为分享我的问题而修改的,让我解释一下。

ChildComponent 自动决定 modelValue 的值是奇数还是偶数。

父组件...

并启动onMounted()中的变量。

但是,我发现 ChildCompoent 中的 watch() 适用于 test1 但不适用于 test3。当我将值推入 test3 或从 test3 中删除值时,watch() 也不适用于 test3。 (当我点击增加按钮时它起作用了。)

请告诉我如何触发 test3watch() 函数。

谢谢。

当然,子组件中的 watch 不是通过从数组中推入或删除元素来触发的。子组件不是在监视整个数组,而是在监视单个元素(它是 val 属性)。

如果将新元素推入数组,则该元素的子组件尚不存在。如果删除一个元素,为该元素呈现的子组件将立即被销毁。唯一可以触发 watch 的确实是 val 属性...

的突变

test2 的问题在于 testNum 是局部临时变量 - 而不是 v-model="testNum",请使用 v-model="test2[index]"

无论如何,你的 ChildComponent.vue 根本不需要 watch。只需使用 computed:

const resultString = computed(() => props.modelValue % 2 === 0 ? 'even' : 'odd')

...顺便说一句,您应该将 keyv-for - docs

一起使用