Vue 2-мутирующий реквизит vue-warn

Vue 2-мутирующий реквизит vue-warn

05.10.2016 11:29:02 Просмотров 37 Источник

Я вздрогнул https://laracasts.com/series/learning-vue-step-by-step серия. Я остановился на уроке Vue, Laravel и AJAX с этой ошибкой:

вю.js: 2574 [Vue warn]: избегайте прямого изменения prop, так как значение будет перезаписываться всякий раз, когда родительский компонент повторно визуализируется. Вместо этого используйте данные или вычисленное свойство, основанное на значении prop. Проп мутирует: "список" (найден в компоненте )

У меня есть этот код в основном.JS

Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    created() {
        this.list = JSON.parse(this.list);
    }
});
new Vue({
    el: '.container'
})

Я знаю, что проблема заключается в created (), когда я перезаписываю список prop, но я новичок в Vue, поэтому я совершенно не знаю, как это исправить. У кого-нибудь есть идея, как (и, пожалуйста, объясните, почему) это исправить?

У вопроса есть решение - Посмотреть?

https://stackoverflow.com/questions/39868963/vue-2-mutating-props-vue-warn#comment67025054_39868963
Думаю, это просто предупреждающее сообщение, а не ошибка.

Ответы - Vue 2-мутирующий реквизит vue-warn / Vue 2 - Mutating props vue-warn

sealla

05.10.2016 12:13:02

Vue просто предупреждает Вас: Вы меняете реквизит в компоненте, но когда родительский компонент повторно визуализируется, "список" будет перезаписан, и вы потеряете все свои изменения. Так что делать это опасно.

Используйте вычисляемое свойство вместо этого, как это:

Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    computed: {
        listJson: function(){
            return JSON.parse(this.list);
        }
    }
});
https://stackoverflow.com/questions/39868963/vue-2-mutating-props-vue-warn/39869897#comment72756554_39869897
А как насчет 2-х сторонней привязки опоры?
https://stackoverflow.com/questions/39868963/vue-2-mutating-props-vue-warn/39869897#comment75472677_39869897
Если вы хотите 2-х стороннюю привязку данных, вы должны использовать пользовательские события, для получения дополнительной информации прочитайте: vuejs.org/v2/guide/components.html#sync-Modifier вы все еще не можете изменить непосредственно prop, вам нужно событие и функция, которая обрабатывает изменение prop для вас.
Является ответом!
ira

07.10.2016 08:47:30

Это связано с тем, что локальная мутация опоры считается анти-паттерном в Vue 2

Теперь, если вы хотите изменить prop локально , вам нужно объявить поле в ваших data, которое использует значение propsв качестве начального значения, а затем изменить копию:

Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    data: function () {
        return {
            mutableList: JSON.parse(this.list);
        }
    }
});

Вы можете прочитать больше об этом на Vue.официальное руководство js


Примечание 1: Пожалуйста, обратите внимание, что вы не должны использовать одно и то же имя для вашего propи data, т. е.:

data: function () { return { list: JSON.parse(this.list) } // WRONG!!

Примечание 2: поскольку я чувствую, что существует некоторая путаница в отношении propи реактивности, я предлагаю вам взглянуть на эту тему

the_haystacker

07.05.2017 10:03:37

Вю.js считает это анти-паттерном. Например, объявление и установка некоторых реквизитов, таких как

this.propsVal = 'new Props Value'

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

props: ['propsVal'],
data: function() {
   return {
       propVal: this.propsVal
   };
},
methods: {
...
}

Это определенно сработает.

Aiwass 418

08.05.2017 10:05:18

Если вы хотите мутировать реквизит-используйте объект.

<component :model="global.price"></component>

деталь:

props: ['model'],
methods: {
  changeValue: function() {
    this.model.value = "new value";
  }
}
https://stackoverflow.com/questions/39868963/vue-2-mutating-props-vue-warn/43841661#comment82713672_43841661
Так же, как и Примечание, Вы должны быть осторожны при изменении объектов. Объекты Javascript передаются по ссылке, но есть один нюанс: ссылка прерывается, когда вы устанавливаете переменную, равную значению.
ihsanberahim

15.06.2017 04:55:26

Я тоже столкнулся с этим вопросом. Предупреждение исчезло после того, как я использую $onи $emit. Это что-то вроде use $onи $emitрекомендуется для отправки данных из дочернего компонента в родительский компонент.

For the Name

21.07.2017 09:34:42

Если вы используете Lodash, вы можете клонировать реквизит, прежде чем вернуть его. Этот шаблон полезен, если вы изменяете эту опору как на родителе, так и на потомке.

Допустим, у нас есть список реквизитов на компонентной сетке .

В Родительском Компоненте

<grid :list.sync="list"></grid>

В Дочернем Компоненте

props: ['list'],
methods:{
    doSomethingOnClick(entry){
        let modifiedList = _.clone(this.list)
        modifiedList = _.uniq(modifiedList) // Removes duplicates
        this.$emit('update:list', modifiedList)
    }
}
edison xue

15.08.2017 04:05:10

Реквизит вниз, события вверх. Это образец вю. Дело в том, что при попытке мутировать реквизит передается от родителя. Он не будет работать, и он просто многократно перезаписывается родительским компонентом. Дочерний компонент может только выдать событие, чтобы уведомить родительский компонент о выполнении sth. Если вам не нравятся эти ограничения, вы можете использовать VUEX(на самом деле этот шаблон будет всасывать сложную структуру компонентов, вы должны использовать VUEX!)

https://stackoverflow.com/questions/39868963/vue-2-mutating-props-vue-warn/45693452#comment82736878_45693452
Также есть возможность использовать шину событий
Potato Running

24.10.2017 01:42:29

Не следует изменять значение реквизита в дочернем компоненте. Если вам действительно нужно изменить его, вы можете использовать .sync. Вот так просто

<your-component :list.sync="list"></your-component>

Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    created() {
        this.$emit('update:list', JSON.parse(this.list))
    }
});
new Vue({
    el: '.container'
})
ubastosir

21.12.2017 01:39:11

Вам нужно добавить вычисляемый метод следующим образом

деталь.вю

props: ['list'],
computed: {
    listJson: function(){
        return JSON.parse(this.list);
    }
}
Francis Leigh

29.12.2017 01:54:53

Вю.JS props не должны мутировать, так как это считается анти-паттерном в Vue.

Подход, который вам нужно будет принять, заключается в создании свойства данных в вашем компоненте, которое ссылается на исходное свойство prop list

props: ['list'],
data: () {
  return {
    parsedList: JSON.parse(this.list)
  }
}

Теперь ваша структура списка, которая передается компоненту, ссылается и мутирует через свойство dataвашего компонента :-)

Если вы хотите сделать больше, чем просто проанализировать свое свойство списка, то используйте computedсвойство компонента Vue. Это позволит вам сделать более глубокие мутации для вашего реквизита.

props: ['list'],
computed: {
  filteredJSONList: () => {
    let parsedList = JSON.parse(this.list)
    let filteredList = parsedList.filter(listItem => listItem.active)
    console.log(filteredList)
    return filteredList
  }
}

Приведенный выше пример анализирует ваш список prop и отфильтровывает его до только активных list-tems, регистрирует его для schnitts и хихикает и возвращает его.

Примечание: оба data& computedссылаются в шаблоне одинаково, например

<pre>{{parsedList}}</pre>

<pre>{{filteredJSONList}}</pre>

Можно легко подумать, что computedсвойство (будучи методом) должно быть вызвано... это не

mryang

04.01.2018 04:44:25

односторонний поток данных, по словам https://vuejs.org/v2/guide/components.html , компонент следовать односторонним поток данных, Все реквизиты образуют одностороннюю привязку между дочерним свойством и родительским, когда родительское свойство обновляется, оно будет стекать вниз к дочернему, но не наоборот, это предотвращает случайное изменение дочерних компонентов родительского, что может затруднить понимание потока данных вашего приложения.

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

Обычно есть два случая, когда заманчиво мутировать реквизит: Prop используется для передачи начального значения; затем дочерний компонент хочет использовать его в качестве локального свойства данных. Пропуск передается в виде необработанного значения, которое необходимо преобразовать. Правильный ответ на эти случаи использования:: Определите локальное свойство данных, которое использует начальное значение prop в качестве своего начального значения:

props: ['initialCounter'],
data: function () {
  return { counter: this.initialCounter }
}

Определите вычисляемое свойство, которое вычисляется из значения prop:

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}
burak buruk

06.02.2018 11:15:58

Согласно VueJs 2.0, вы не должны мутировать опору внутри компонента. Они мутируют только от своих родителей. Поэтому следует определять переменные в данных с разными именами и обновлять их, наблюдая за фактическими реквизитами. В случае, если список prop изменен родителем, вы можете разобрать его и назначить его mutableList. Вот полное решение.

Vue.component('task', {
    template: ´<ul>
                  <li v-for="item in mutableList">
                      {{item.name}}
                  </li>
              </ul>´,
    props: ['list'],
    data: function () {
        return {
            mutableList = JSON.parse(this.list);
        }
    },
    watch:{
        list: function(){
            this.mutableList = JSON.parse(this.list);
        }
    }
});

Он использует mutableList для визуализации вашего шаблона, таким образом, вы держите свой список prop безопасным в компоненте.

Tango5614

01.03.2018 08:27:38

не меняйте реквизит непосредственно в компонентах.если вам нужно изменить его установите новое свойство как это:

data () {
    return () {
        listClone: this.list
    }
}

И измените значение listClone.

chris

07.08.2018 11:21:43

Шаблон Vue-это propsвниз и eventsвверх. Это звучит просто, но легко забыть при написании пользовательского компонента.

Начиная с версии Vue 2.2.0 вы можете использовать v-модель вычисляемыми свойствами ). Я обнаружил, что эта комбинация создает простой, чистый и последовательный интерфейс между компонентами:

  • Любой props, передаваемый вашему компоненту, остается реактивным (т. е. он не клонируется и не требует watchпереписать компонент задачи следующим образом:

    Task

    Свойство model определяет, какой Vue.component('Task', { template: '#task-template', props: ['list'], model: { prop: 'list', event: 'listchange' }, computed: { listLocal: { get: function() { return this.list }, set: function(value) { this.$emit('listchange', value) } } } }) связан с prop, и какое событие будет выдано при изменениях. Затем вы можете вызвать этот компонент из родительского объекта следующим образом:

    Task

    Свойство <Task v-model="parentList"></Task> computed предоставляет простой интерфейс getter и setter в компоненте (думайте о нем как о частной переменной). В #task-templateвы можете сделать #task-template, и он останется реактивным (т. е., если Taskизменится, он обновит компонент parentList). Вы также можете изменить #task-template, вызвав сеттер (например, listLocal), и он выдаст изменение родителю.

    Что замечательно в этом шаблоне, так это то, что вы можете передать this.listLocal = newListдочернему компоненту listLocal(используя prop), и изменения из дочернего компонента будут распространяться на компонент верхнего уровня.

    Например, предположим, что у нас есть отдельный v-modelи шаблон вычисляемых свойств, мы можем передать EditTask):

    v-model

    Если listLocalвыдаст изменение, он соответствующим образом вызовет v-modelна this.listLocal = newListи таким образом распространит событие на верхний уровень. Аналогично, EditTask.

https://stackoverflow.com/questions/39868963/vue-2-mutating-props-vue-warn/51722100#comment91772354_51722100
Я делаю нечто подобное, но только с синхронизацией. Проблема заключается в том, что мне нужно запустить другой метод после отправки моего события изменения, однако, когда метод запускается и попадает в геттер, я получаю старое значение, потому что событие изменения еще не было подхвачено слушателем / распространено обратно к дочернему объекту. Это тот случай, когда я хочу изменить prop, чтобы мои локальные данные были правильными, пока родительское обновление не распространится обратно вниз. Есть какие-нибудь мысли на этот счет?
https://stackoverflow.com/questions/39868963/vue-2-mutating-props-vue-warn/51722100#comment91797199_51722100
Я подозреваю, что звонить добытчику от сеттера-не очень хорошая практика. То, что вы могли бы рассмотреть, - это поставить часы на ваше вычисляемое свойство и добавить туда свою логику.
https://stackoverflow.com/questions/39868963/vue-2-mutating-props-vue-warn/51722100#comment93141802_51722100
реквизит вниз и события вверх-вот что щелкнуло со мной. Где это объясняется в документах VueJs?
https://stackoverflow.com/questions/39868963/vue-2-mutating-props-vue-warn/51722100#comment98295111_51722100
@nebulousGirl посмотрите здесь: vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow
https://stackoverflow.com/questions/39868963/vue-2-mutating-props-vue-warn/51722100#comment104410037_51722100
Я думаю, что это более безболезненный способ передачи изменений в родительский компонент.
Maroun Melhem

16.11.2018 02:30:14

В дополнение к вышесказанному, для других лиц, имеющих следующие проблемы:

"Если значение реквизита не требуется и, следовательно, не всегда возвращается, переданные данные будут возвращены undefined(вместо пустых)". Которые могли бы испортить <select> значение по умолчанию, я решил ее проверить, если значение находится в beforeMount() (и установить его, если нет) следующим образом:

JS:

export default {
        name: 'user_register',
        data: () => ({
            oldDobMonthMutated: this.oldDobMonth,
        }),
        props: [
            'oldDobMonth',
            'dobMonths', //Used for the select loop
        ],
        beforeMount() {
           if (!this.oldDobMonth) {
              this.oldDobMonthMutated = '';
           } else {
              this.oldDobMonthMutated = this.oldDobMonth
           }
        }
}

Формат html:

<select v-model="oldDobMonthMutated" id="dob_months" name="dob_month">

 <option selected="selected" disabled="disabled" hidden="hidden" value="">
 Select Month
 </option>

 <option v-for="dobMonth in dobMonths"
  :key="dobMonth.dob_month_slug"
  :value="dobMonth.dob_month_slug">
  {{ dobMonth.dob_month_name }}
 </option>

</select>
D.P

14.12.2018 12:56:31

Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    computed: {
      middleData() {
        return this.list
      }
    },
    watch: {
      list(newVal, oldVal) {
        console.log(newVal)
        this.newList = newVal
      }
    },
    data() {
      return {
        newList: {}
      }
    }
});
new Vue({
    el: '.container'
})

Возможно, это удовлетворит ваши потребности.

YuuwakU

02.02.2019 10:55:29

Добавление к лучшему ответу,

Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    data: function () {
        return {
            mutableList: JSON.parse(this.list);
        }
    }
});

Установка реквизитов массивом предназначена для разработки/прототипирования, в производстве обязательно установите типы реквизитов( https://vuejs.org/v2/guide/components-props.html ) и установите значение по умолчанию в случае, если prop не был заполнен родителем, как это было сделано.

Vue.component('task', {
    template: '#task-template',
    props: {
      list: {
        type: String,
        default() {
          return '{}'
        }
      }
    },
    data: function () {
        return {
            mutableList: JSON.parse(this.list);
        }
    }
});

Таким образом, вы по крайней мере получите пустой объект в mutableListвместо JSON.ошибка синтаксического анализа, если она не определена.

Mr.Web

27.09.2019 08:51:52

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

Реквизит предназначен для обеспечения односторонней связи.

Когда у вас есть модальная show/hideс опорой, лучшим решением для меня является создание события:

<button @click="$emit('close')">Close Modal</button>

Затем добавьте слушателя к модальному элементу:

<modal :show="show" @close="show = false"></modal>

(В этом случае prop show, вероятно, не нужен, потому что вы можете использовать простой v-if="show"непосредственно на базовой модальности)

mohit dutt

19.10.2019 05:11:26

Я лично всегда предлагаю, если вам нужно мутировать реквизит, сначала передать его в вычисляемую собственность и вернуться оттуда, после чего можно легко мутировать реквизит, даже если вы можете отслеживать мутацию реквизита, если они тоже мутируют из другого компонента, или мы можем вас также наблюдать .

flypan

18.11.2019 09:35:44

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

Из официального документа Vue мы найдем 2 способа решения этой проблемы

  1. если дочерний компонент хочет использовать props в качестве локальных данных, то лучше всего определить свойство локальных данных.

      props: ['list'],
      data: function() {
        return {
          localList: JSON.parse(this.list);
        }
      }
    
    
  2. Пропуск передается в виде необработанного значения, которое необходимо преобразовать. В этом случае лучше всего определить вычисляемое свойство, используя значение prop:

      props: ['list'],
      computed: {
        localList: function() {
           return JSON.parse(this.list);
        },
        //eg: if you want to filter this list
        validList: function() {
           return this.list.filter(product => product.isValid === true)
        }
        //...whatever to transform the list
      }
    
    
    
Vectrobyte

26.11.2019 12:42:55

Ответ прост, вы должны сломать прямую мутацию prop, присвоив значение некоторым локальным компонентным переменным (это может быть свойство данных, вычисляемое с помощью геттеров, сеттеров или наблюдателей).

Вот простое решение с помощью наблюдателя.

<template>
  <input
    v-model="input"
    @input="updateInput" 
    @change="updateInput"
  />

</template>

<script>
  export default {
  props: {
    value: {
      type: String,
      default: '',
    },
  },
  data() {
    return {
      input: '',
    };
  },
  watch: {
    value: {
      handler(after) {
        this.input = after;
      },
      immediate: true,
    },
  },
  methods: {
    updateInput() {
      this.$emit('input', this.input);
    },
  },
};
</script>

Это то, что я использую для создания любых компонентов ввода данных, и это работает просто отлично. Любые новые данные, отправленные(v-model (ed)) от родителя, будут отслеживаться наблюдателем значений и назначаться входной переменной, и как только входные данные будут получены, мы можем поймать это действие и выдать входные данные родителю, предполагая, что данные вводятся из элемента формы.

Ali

03.01.2020 03:43:42

Да!, мутирующие атрибуты в vue2-это анти-паттерн. НО... Просто нарушайте правила, используя другие правила, и идите вперед! Что вам нужно, так это добавить .модификатор синхронизации с атрибутом компонента в области paret. <your-awesome-components :custom-attribute-as-prob.sync="value" />

Закрыть X