J'ai commencé https://laracasts.com/series/learning-vue-step-by-step series. Je me suis arrêté sur la leçon Vue, Laravel et AJAX avec cette erreur:
vue.js:2574 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "list" (found in component <task>)
J'ai ce code dans main.js
Vue.component('task', {
template: '#task-template',
props: ['list'],
created() {
this.list = JSON.parse(this.list);
}
});
new Vue({
el: '.container'
})
Je sais que le problème réside dans created () lorsque j'écrase la propriété prop, mais je suis un débutant dans Vue, je ne sais donc absolument pas comment le résoudre. Quelqu'un a une idée comment (et s'il vous plaît expliquer pourquoi) comment le réparer?
Ceci est dû au fait que la mutation d'un accessoire localement est considéré comme un anti-motif dans Vue 2
Ce que vous devriez faire maintenant, au cas où vous voudriez transformer un prop localement}, est de déclarer un champ dans votre data
qui utilise la valeur props
comme valeur initiale, puis de muter la copie:
Vue.component('task', {
template: '#task-template',
props: ['list'],
data: function () {
return {
mutableList: JSON.parse(this.list);
}
}
});
Vous pouvez en lire plus à ce sujet sur Le guide officiel de Vue.js
Note 1: Veuillez noter que vous devriez pas utiliser le même nom pour votre prop
et data
, c'est-à-dire:
data: function () { return { list: JSON.parse(this.list) } // WRONG!!
Note 2: Depuis je sens qu'il y a une certaine confusion en ce qui concerne props
et réactivité, je vous suggère de jeter un coup d'œil sur this thread
Vue vous avertit simplement: vous modifiez l'accessoire dans le composant, mais lorsque le composant parent sera restitué, "list" sera écrasé et vous perdrez toutes vos modifications. C'est donc dangereux de le faire.
Utilisez la propriété calculée à la place comme ceci:
Vue.component('task', {
template: '#task-template',
props: ['list'],
computed: {
listJson: function(){
return JSON.parse(this.list);
}
}
});
Props down, événements en place. C'est le motif de Vue. Le fait est que si vous essayez de muter un accessoire en passant de parent. Cela ne fonctionnera pas et sera simplement écrasé de manière répétée par le composant parent. Le composant enfant ne peut émettre un événement que pour informer le composant parent de le faire. Si vous n'aimez pas ces restrictions, vous pouvez utiliser VUEX (en fait, ce modèle aspire la structure de composants complexes, vous devriez utiliser VUEX!)
Si vous utilisez Lodash, vous pouvez cloner l'accessoire avant de le renvoyer. Ce modèle est utile si vous modifiez cet accessoire à la fois du parent et de l'enfant.
Disons que nous avons prop list sur le composant grid.
Dans la composante parentale
<grid :list.sync="list"></grid>
Dans la composante enfant
props: ['list'],
methods:{
doSomethingOnClick(entry){
let modifiedList = _.clone(this.list)
modifiedList = _.uniq(modifiedList) // Removes duplicates
this.$emit('update:list', modifiedList)
}
}
Le modèle Vue est simple: props
down et events
up. Cela semble simple, mais il est facile de l'oublier lors de l'écriture d'un composant personnalisé.
A partir de Vue 2.2.0, vous pouvez utiliser v-model (avec propriétés calculées ). Je trouve que cette combinaison crée une interface simple, propre et cohérente entre les composants:
props
transmise à votre composant reste réactive (c’est-à-dire qu’elle n’est pas clonée ni ne requiert une fonction watch
pour mettre à jour une copie locale lorsque des modifications sont détectées).Une propriété calculée permet de définir séparément le getter et le getter. Cela permet au composant Task
d'être réécrit comme suit:
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)
}
}
}
})
La propriété model définit quelle prop
est associée à v-model
et quel événement sera émis lors des modifications. Vous pouvez ensuite appeler ce composant à partir du parent comme suit:
<Task v-model="parentList"></Task>
La propriété calculée listLocal
fournit une interface getter/setter simple au sein du composant (pensez-y comme une variable privée). Dans #task-template
, vous pouvez rendre listLocal
et il restera réactif (c.-à-d. Si parentList
change, le composant Task
sera mis à jour). Vous pouvez également muter listLocal
en appelant le setter (par exemple, this.listLocal = newList
) et le changement sera transmis au parent.
Ce qui est génial avec ce modèle, c'est que vous pouvez passer listLocal
à un composant enfant de Task
(à l'aide de v-model
), et les modifications apportées par le composant enfant seront propagées au composant de niveau supérieur.
Par exemple, supposons que nous ayons un composant EditTask
distinct pour effectuer un certain type de modification des données de la tâche. En utilisant le même modèle v-model
et les propriétés calculées, nous pouvons transmettre listLocal
au composant (à l'aide de v-model
):
<script type="text/x-template" id="task-template">
<div>
<EditTask v-model="listLocal"></EditTask>
</div>
</script>
Si EditTask
émet une modification, il appelle de manière appropriée set()
sur listLocal
et propage ainsi l'événement au niveau supérieur. De même, le composant EditTask
peut également appeler d'autres composants enfants (tels que des éléments de formulaire) à l'aide de v-model
.
Vous ne devez pas modifier la valeur des accessoires dans le composant enfant . Si vous devez réellement la modifier, vous pouvez utiliser .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'
})
Selon VueJs 2.0, vous ne devez pas muter un accessoire dans le composant. Ils sont seulement mutés par leurs parents. Par conséquent, vous devez définir des variables dans les données avec des noms différents et les maintenir à jour en surveillant les accessoires réels . Si la propriété est modifiée par un parent, vous pouvez l'analyser et l'assigner à mutableList. Voici une solution complète.
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);
}
}
});
Il utilise mutableList pour rendre votre modèle, vous gardez ainsi votre liste prop dans le composant.
ne changez pas les accessoires directement dans components.Si vous devez le changer, définissez une nouvelle propriété comme celle-ci:
data () {
return () {
listClone: this.list
}
}
Et changez la valeur de listClone.
J'ai également fait face à ce problème. L'avertissement a disparu après l'utilisation de $on
et $emit
. C'est un peu comme utiliser $on
et $emit
recommandé d'envoyer des données du composant enfant au composant parent.
flux de données unidirectionnel, .__ selon https://vuejs.org/v2/guide/components.html , le composant suit un sens... Flux de données, Tous les accessoires forment un liaison unidirectionnelle entre la propriété enfant et la propriété parent; lorsque la propriété parent est mise à jour, elle se répercute sur l'enfant, mais pas l'inverse, cela empêche les composants enfants de transformer accidentellement ceux du parent, ce qui peut rendre votre application flux de données plus difficile à comprendre.
De plus, chaque fois que le composant parent est mis à jour, tous les objets proposésdans les composants enfants sont actualisés avec la dernière valeur. Cela signifie que vous ne devez pas tenter de muter un accessoire dans un composant enfant. Si vous le faites, .vue vous avertira dans la console
Il existe généralement deux cas dans lesquels il est tentant de muter un accessoire: L’accessoire est utilisé pour transmettre une valeur initiale; le composant enfant souhaite l'utiliser par la suite en tant que propriété de données locale . L'accessoire est transmis en tant que valeur brute devant être transformée . La réponse appropriée à ces cas d'utilisation est la suivante: Définir une valeur locale propriété de données qui utilise la valeur initiale du prop comme valeur initiale:
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
Définissez une propriété calculée calculée à partir de la valeur de prop:
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
Si vous voulez muter les accessoires, utilisez object.
<component :model="global.price"></component>
composant:
props: ['model'],
methods: {
changeValue: function() {
this.model.value = "new value";
}
}
Vous devez ajouter une méthode calculée comme ceci
composant.vue
props: ['list'],
computed: {
listJson: function(){
return JSON.parse(this.list);
}
}
Ajoutant à la meilleure réponse,
Vue.component('task', {
template: '#task-template',
props: ['list'],
data: function () {
return {
mutableList: JSON.parse(this.list);
}
}
});
Le paramétrage des accessoires par un tableau est destiné au développement/prototypage. En production, assurez-vous de définir les types d’accessoires ( https://vuejs.org/v2/guide/components-props.html ) et définissez une valeur par défaut dans le cas contraire. l'accessoire n'a pas été peuplé par le parent, comme tel.
Vue.component('task', {
template: '#task-template',
props: {
list: {
type: String,
default() {
return '{}'
}
}
},
data: function () {
return {
mutableList: JSON.parse(this.list);
}
}
});
De cette façon, vous obtenez au moins un objet vide dans mutableList
au lieu d’une erreur JSON.parse s’il n’est pas défini.
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'
})
Peut-être que cela répondra à vos besoins.
Les accessoires de Vue.js ne doivent pas être mutés car ceci est considéré comme un anti-modèle dans Vue.
L'approche que vous devez adopter consiste à créer une propriété de données sur votre composant qui référence la propriété originale prop de list.
props: ['list'],
data: () {
return {
parsedList: JSON.parse(this.list)
}
}
Maintenant, votre structure de liste transmise au composant est référencée et mutée via la propriété data
de votre composant :-)
Si vous souhaitez faire plus que simplement analyser votre propriété list, utilisez alors la propriété computed
du composant Vue .. Cela vous permet de faire des mutations plus en profondeur de vos accessoires.
props: ['list'],
computed: {
filteredJSONList: () => {
let parsedList = JSON.parse(this.list)
let filteredList = parsedList.filter(listItem => listItem.active)
console.log(filteredList)
return filteredList
}
}
L'exemple ci-dessus analyse votre list prop et le filtre en seulement actif list-tems, le déconnecte pour les commandes et les rires et le renvoie.
note: les deux propriétés data
& computed
sont référencées dans le modèle de la même manière, par exemple
<pre>{{parsedList}}</pre>
<pre>{{filteredJSONList}}</pre>
Il peut être facile de penser qu’une propriété computed
(étant une méthode) doit être appelée ... elle ne le fait pas.
Vue.js considère cela comme un anti-motif. Par exemple, en déclarant et en définissant des accessoires comme
this.propsVal = 'new Props Value'
Donc, pour résoudre ce problème, vous devez prendre une valeur allant des accessoires aux données ou à la propriété calculée d'une instance de Vue, comme ceci:
props: ['propsVal'],
data: function() {
return {
propVal: this.propsVal
};
},
methods: {
...
}
Cela fonctionnera certainement.