Почему при использовании NumericTextField появляется сообщение «Избегайте мутации напрямую»? - PullRequest
0 голосов
/ 18 марта 2019

Я создал компонент простого представления в VueJS, и я получаю довольно распространенную ошибку:

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

Вот мой код:

<template>
    <numeric-text-field class="mx-auto" label="Head Mass" units="kg" v-model="turbine.head_mass" />
</template>

<script>
import NumericTextField from '@/components/common/NumericTextField'
export default {
  name: 'Turbines',
  components: {
    NumericTextField
  },
  data () {
    return {
      turbine: {}
    }
  }
}
</script>

<style scoped>
</style>

Как ни странно, я получаю ошибку для изменения «значения», но у меня нет значения в моемкод.Я думаю, что это вызвано косвенным слоем, созданным числовым текстовым полем.Эта проблема не существует в моем коде, когда я использую только обычный ввод текста.Что здесь происходит?Есть ли другой особый способ, которым я должен подключить модель к моим числовым текстовым полям, кроме v-model?

Ответы [ 2 ]

0 голосов
/ 18 марта 2019

Это оказывается без моего ведома после первоначальной публикации и выпуска в NumericTextField. Я думал, что это стандартный компонент Vueify, но был добавлен коллегой. Он неправильно обрабатывал двунаправленный ввод, как указано в комментариях к исходному сообщению.

Хитрость заключается в том, чтобы добавить это. $ Emit ('input', value) из компонента NumericTextField в @input, как предложил Ohgodwhy.

0 голосов
/ 18 марта 2019

Важно понимать, как реквизит работает в Vue. Ключевым аспектом здесь является то, что реквизиты используются для одностороннего потока данных . Если вы хотите, чтобы это был двусторонний поток данных, вам нужно вместо этого использовать v-model.

Сказав это, есть несколько разных способов сделать это. Я предпочитаю использовать вычисленные свойства для подобных вещей! Это довольно чисто, и легко следовать в коде.

Вместо того, чтобы модифицировать опору напрямую, в вашем numeric-text-field компоненте вы должны вместо этого генерировать событие, когда значение изменено. Вот как будет выглядеть Turbines.vue:

<template>
    <numeric-text-field class="mx-auto"
    label="Head Mass"
    units="kg"
    :headMass="turbine.head_mass"
    v-on:updateHeadMass="updateHeadMass"/>
</template>

<script>
import NumericTextField from '@/components/common/NumericTextField'
export default {
  name: 'Turbines',
  components: {
    NumericTextField
  },
  data () {
    return {
      // You should consider initializing your data with the structure that matches what you expect, instead of an empty object
      turbine: {
        head_mass: ""
      }
    }
  },
  methods: {
    updateHeadMass(value) {
      this.turbines.head_mass = value;
    }
  }
}
</script>

<style scoped>
</style>

Вы заметите атрибут v-on:updateHeadMass. Вот как мы слушаем испущенные события от наших дочерних компонентов. Когда выдается даже updateHeadMass, мы можем вызвать определенную функцию и соответственно обновить наши данные в родительском компоненте. Это приведет к реактивному изменению дочернего компонента, который затем обновляется.

Внутри NumericTextField

Вместо прямого изменения реквизита, используйте вычисляемое свойство, которое генерирует событие, вплоть до родительского компонента при изменении ввода Вот как может выглядеть ваш NumericTextField компонент:

<template>
  <div>
    <label for="headMass">Head Mass</label>
    <input type="text" v-model="localHeadMass"  name="headMass"/>
  </div>
</template>

<script>
export default {
  name: "numeric-text-field",
  computed: {
    localHeadMass: {
      get() {
        return this.headMass;
      },
      set(value) {
        // Now, anytime we change this property, our parent receives the new value and updates the `headMass` prop!
        this.$emit("updateHeadMass", value);
      }
    }
  },
  props: {
    headMass: {
      type: String,
      default: "0",
      required: true
    }
  }
};
</script>

<style scoped>
</style>

Если вам не нужен вышеуказанный подход, вместо этого вы можете использовать наблюдателя, подобного этому:

<template>
  <div>
    <label for="headMass">Head Mass</label>
    <input type="text" v-model="localHeadMass" v-on:change="updateHeadMass" name="headMass"/>
  </div>
</template>

<script>
export default {
  name: "numeric-text-field",
  data: () => {
    return {
      localHeadMass: ""
    };
  },
  props: {
    headMass: {
      type: String,
      default: "0",
      required: true
    }
  },
  methods: {
    updateHeadMass() {
      this.$emit("updateHeadMass", this.localHeadMass);
    }
  },
  watch: {
    headMass(value) {
      this.localHeadMass = value;
    }
  }
};
</script>

<style scoped>
</style>
...