Vue 2 - 变异道具 vue-warn

2022-08-30 00:14:48

我开始 https://laracasts.com/series/learning-vue-step-by-step 系列。我在 Vue、Laravel 和 AJAX 课程中停止了这个错误:

vue.js:2574 [Vue warn]:避免直接改变 prop,因为每当父组件重新呈现时,值都会被覆盖。相反,请使用基于 prop 值的数据或计算属性。道具正在变异:“列表”(在组件中找到)

我在main中有这个代码.js

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

我知道当我覆盖列表道具时,问题出在create()中,但我是Vue中的新手,所以我完全不知道如何解决它。有谁知道如何(并请解释原因)来修复它?


答案 1

这与在 Vue 2 中局部变异 prop 被认为是一种反模式有关。

如果你想在本地改变一个 prop,你现在应该做的是在 your 中声明一个字段,该字段使用该值作为其初始值,然后改变副本:dataprops

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

你可以在 Vue 上阅读更多相关信息.js官方指南


注1:请注意,不应为您的道具数据使用相同的名称,即:

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

注2:由于我觉得在反应性和反应性方面存在一些混淆,我建议您看看这个线程props


答案 2

Vue 模式是向下和向上的。这听起来很简单,但在编写自定义组件时很容易忘记。propsevents

从 Vue 2.2.0 开始,你可以使用 v-model(具有计算属性)。我发现这种组合在组件之间创建了一个简单,干净且一致的界面:

  • 传递给组件的任何内容都是反应式的(即,它不是克隆的,也不需要在检测到更改时更新本地副本的函数)。propswatch
  • 更改将自动发出给父级。
  • 可与多级组件一起使用。

计算属性允许分别定义 setter 和 getter。这允许按如下方式重写组件:Task

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

model 属性定义哪个与 相关联,以及在发生更改时将发出哪个事件。然后,您可以从父级调用此组件,如下所示:propv-model

<Task v-model="parentList"></Task>

计算属性在组件中提供了一个简单的 getter 和 setter 接口(可以将其视为私有变量)。在你可以渲染的情况下,它将保持反应性(即,如果更改,它将更新组件)。您也可以通过调用 setter(例如 ,)来进行更改,它将向父级发出更改。listLocal#task-templatelistLocalparentListTasklistLocalthis.listLocal = newList

此模式的优点在于,您可以将 传递给 (using ) 的子组件,并且从子组件的更改将传播到顶级组件。listLocalTaskv-model

例如,假设我们有一个单独的组件,用于对任务数据进行某种类型的修改。通过使用相同的计算属性模式,我们可以传递给组件(使用):EditTaskv-modellistLocalv-model

<script type="text/x-template" id="task-template">
    <div>
        <EditTask v-model="listLocal"></EditTask>
    </div>
</script>

如果发出更改,它将适当地调用,从而将事件传播到顶层。同样,该组件也可以使用 调用其他子组件(如表单元素)。EditTaskset()listLocalEditTaskv-model