Потеря реактивности: Как использовать «глубокий» вычислительный сеттер

#vue.js #vuejs3

Вопрос:

У меня есть модальный компонент, который получает объект как v-model . Этот объект содержит некоторые ключи, такие как id или name .

Теперь, если я сделаю это:

 <template>
    <div class="h-2/3 w-2/3 bg-green-500">
        <input v-model="computedValue.id" />
        {{computedValue}}
    </div>
</template>
<script>

export default {
    name: 'TestModal',
    props: {
        modelValue: {
            type: Object,
        },
    },
    emits: ["update:modelValue"],
    data: () => ({
    }),
    computed: {
        computedValue: {
            get() {
                return this.modelValue;
            },
            set(newValue) {
                console.log("computedValue?")
                this.$emit('update:modelValue', newValue)
            }
        },
    },
    methods: {
    },
}
</script>
 

он console.log("computedValue?") никогда не срабатывает, а также излучение не срабатывает.

Как я могу использовать «глубокий сеттер»?

Комментарии:

1. Смысл операций чтения-записи в том, что они могут быть либо прочитаны, либо записаны. Позволить ему мутировать v-model="computedValue.id" — это ошибка.

Ответ №1:

Подход, который я использую для этого, заключается в следующем. Возьмите начальную «копию» свойства в качестве переменной данных ( rwModel ). Используйте v-model для взаимодействия с этой переменной, затем используйте наблюдателя для запуска события/выполнения некоторой работы всякий раз, когда переменная изменяется.

Преимущество в том, что вы никогда не пытаетесь изменить свойство, но вы также делаете минимум, чтобы избежать этого, поэтому его по-прежнему легко проверить и понять. Вы также можете получить старое значение в наблюдателе, что упрощает сравнение.

В качестве альтернативы вместо просмотра вы можете легко изменить это, чтобы иметь событие, которое запускает что — то с обновленными данными-например, кнопку сохранения в форме.

 <template>
    <div class="h-2/3 w-2/3 bg-green-500">
        <input v-model="rwModel.id" />
        {{rwModel}}
    </div>
</template>
<script>

export default {
    props: {
        modelValue: {
            type: Object,
        },
    },
    emits: ["update:modelValue"],
    data() {
      return {
        rwModel: this.modelValue,
      }
    },
    watch: {
      modelValue: {
        deep: true,
        handler(newValue) {
          console.log("watchedValue?")
          this.$emit('update:modelValue', newValue)
        },
      },
    },
}
</script>
 

Ответ №2:

Что происходит: На <input> элементе, v-model="property" по сути, эквивалентно
:value="property" @input="property = $event" ,

что в вашем коде переводится как
:value="computedValue.id" @input="computedValue.id = $event" .

Это установит идентификатор, но вычисляемый установщик никогда не сработает, так как вы устанавливаете computedValue .

Решение: Поскольку вы хотите использовать внутреннее свойство, вам нужен более точный контроль над событием @input. Таким образом, вы можете просто заменить свои входные данные
v-model="computedValue.id" с
:value="computedValue.id" @input="computedValue = $event"

Это вызовет ваш вычисляемый сеттер и выведет инструкцию консоли.

Примечание: Даже если computedValue = $event это выглядит так, как будто мы устанавливаем computedValue значение ввода, это не так. Поскольку мы написали сеттер для вычисляемого свойства, Vue разумно запускает сеттер при выполнении инструкции.

Комментарии:

1. Это отличная работа. Но, если у вас есть массив или объект в качестве опоры, вы потеряли реактивное вычисляемое свойство. Даже выдача изменений Vue не может обнаружить изменения в реквизите.