Vue 2-мутирующий реквизит vue-warn
Я вздрогнул 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, поэтому я совершенно не знаю, как это исправить. У кого-нибудь есть идея, как (и, пожалуйста, объясните, почему) это исправить?

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

05.10.2016 12:13:02
Vue просто предупреждает Вас: Вы меняете реквизит в компоненте, но когда родительский компонент повторно визуализируется, "список" будет перезаписан, и вы потеряете все свои изменения. Так что делать это опасно.
Используйте вычисляемое свойство вместо этого, как это:
Vue.component('task', {
template: '#task-template',
props: ['list'],
computed: {
listJson: function(){
return JSON.parse(this.list);
}
}
});



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
и реактивности, я предлагаю вам взглянуть на эту тему

07.05.2017 10:03:37
Вю.js считает это анти-паттерном. Например, объявление и установка некоторых реквизитов, таких как
this.propsVal = 'new Props Value'
Таким образом, чтобы решить эту проблему, вы должны принять значение от реквизитов к данным или вычисленному свойству экземпляра Vue, как это:
props: ['propsVal'],
data: function() {
return {
propVal: this.propsVal
};
},
methods: {
...
}
Это определенно сработает.

08.05.2017 10:05:18
Если вы хотите мутировать реквизит-используйте объект.
<component :model="global.price"></component>
деталь:
props: ['model'],
methods: {
changeValue: function() {
this.model.value = "new value";
}
}


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

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)
}
}

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


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'
})


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
свойство (будучи методом) должно быть вызвано... это не

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()
}
}

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 безопасным в компоненте.


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
.






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>

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'
})
Возможно, это удовлетворит ваши потребности.

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.ошибка синтаксического анализа, если она не определена.

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"
непосредственно на базовой модальности)

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

18.11.2019 09:35:44
Поскольку Vue props-это один из способов передачи данных, это предотвращает случайное изменение состояния родительского компонента дочерними компонентами.
Из официального документа Vue мы найдем 2 способа решения этой проблемы
если дочерний компонент хочет использовать props в качестве локальных данных, то лучше всего определить свойство локальных данных.
props: ['list'], data: function() { return { localList: JSON.parse(this.list); } }
Пропуск передается в виде необработанного значения, которое необходимо преобразовать. В этом случае лучше всего определить вычисляемое свойство, используя значение 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 }

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)) от родителя, будут отслеживаться наблюдателем значений и назначаться входной переменной, и как только входные данные будут получены, мы можем поймать это действие и выдать входные данные родителю, предполагая, что данные вводятся из элемента формы.

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