我开始了https://laracasts.com/series/learning-vue-step-by-step系列。我在Vue、Laravel和AJAX的课程上停了下来,出现了这个错误:

Vue .js:2574 [Vue警告]:避免直接改变道具,因为每当父组件重新呈现时,该值将被覆盖。相反,应该使用基于道具值的数据或计算属性。道具被突变:"list"(在组件中找到)

我在main.js中有这段代码

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

我知道,当我覆盖列表道具时,问题是在created(),但我是Vue的新手,所以我完全不知道如何修复它。有人知道如何(请解释为什么)解决这个问题吗?


当前回答

我想给出这个答案,这有助于避免使用大量的代码,观察者和计算属性。在某些情况下,这可能是一个很好的解决方案:

道具是用来提供单向交流的。

当你有一个带有道具的模态显示/隐藏按钮时,对我来说最好的解决方案是发出一个事件:

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

然后添加监听器到模态元素:

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

(在这种情况下,道具显示可能是不必要的,因为你可以直接在基本模式上使用简单的v-if="show")

其他回答

Vue.js认为这是一个反模式。例如,声明和设置一些道具

this.propsVal = 'new Props Value'

所以为了解决这个问题,你必须从数据或Vue实例的计算属性的道具中获取一个值,就像这样:

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

这肯定有用。

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

也许这个能满足你的需要。

下面是一个小吃店组件,当我把小吃店变量直接输入v-model,就像这样,如果将工作,但在控制台中,它会给出一个错误

避免直接改变道具,因为每当父组件重新呈现时,该值将被覆盖。相反,应该使用基于道具值的数据或计算属性。

<template>
        <v-snackbar v-model="snackbar">
        {{ text }}
      </v-snackbar>
</template>

<script>
    export default {
        name: "loader",
     
        props: {
            snackbar: {type: Boolean, required: true},
            text: {type: String, required: false, default: ""},
        },
      
    }
</script>

消除这种变异错误的正确方法是使用监测器

<template>
        <v-snackbar v-model="snackbarData">
        {{ text }}
      </v-snackbar>
</template>

<script>
/* eslint-disable */ 
    export default {
        name: "loader",
         data: () => ({
          snackbarData:false,
        }),
        props: {
            snackbar: {type: Boolean, required: true},
            text: {type: String, required: false, default: ""},
        },
        watch: { 
        snackbar: function(newVal, oldVal) { 
          this.snackbarData=!this.snackbarDatanewVal;
        }
      }
    }
</script>

在加载小吃店的主组件中,你可以执行这段代码

<loader :snackbar="snackbarFlag" :text="snackText"></loader>

这对我很有用

根据VueJs 2.0,您不应该改变组件内部的道具。它们只会被父母变异。因此,您应该在数据中定义不同名称的变量,并通过观察实际的道具来更新它们。 如果列表道具被父元素更改,您可以解析它并将其分配给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);
        }
    }
});

它使用mutableelist来呈现模板,这样就可以在组件中保证列表道具的安全。

如果您正在使用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)
    }
}