Vue 2 - 改变props vue-warn

IT技术 javascript vue.js vuejs2
2021-01-24 01:41:14

我开始了https://laracasts.com/series/learning-vue-step-by-step系列。我在学习Vue、Laravel 和 AJAX遇到了这个错误:

vue.js:2574 [Vue 警告]:避免直接改变 prop,因为每当父组件重新渲染时,该值将被覆盖。相反,根据props的值使用数据或计算属性。正在变异的props:“列表”(在组件中找到)

我在main.js 中有这段代码

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

我知道当我覆盖 list 属性时问题出在created() 中,但我是 Vue 的新手,所以我完全不知道如何解决它。任何人都知道如何(并请解释原因)修复它?

6个回答

这与在 Vue 2 中本地改变 prop 被认为是反模式的事实有关

如果您想在本地更改prop您现在应该做的是声明一个字段,该字段data使用该props值作为其初始值,然后更改副本:

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

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


注1:请注意,您应该为你使用相同的名称propdata,即:

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

注2:由于我觉得关于propsreact性有些混乱,我建议你看看这个线程

@WesHarper,还可以使用.sync 修饰符作为速记来自动获取父级的更新事件。
2021-03-21 01:41:14
这是一个很好的答案,但我也认为应该更新它以包含事件绑定。从孩子触发的事件可以更新父母,这会将更新的道具传递给孩子。这样,所有组件中仍然保持真实来源。值得一提的是 Vuex 用于管理跨多个组件共享的状态。
2021-04-11 01:41:14

Vue公司的模式是props下来events了。这听起来很简单,但在编写自定义组件时很容易忘记。

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

  • props传递给您的组件的任何内容都保持react性(即,它不会被克隆,也不需要watch在检测到更改时更新本地副本函数)。
  • 更改会自动发送到父级。
  • 可以与多个级别的组件一起使用。

计算属性允许分别定义 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)
            }
        }
    }
})  

模型,其属性定义prop相关联v-model,并且该事件将在改变发射。然后,您可以从父级调用此组件,如下所示:

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

所述listLocal计算出的属性在组件内提供了一个简单的getter和setter接口(认为它像被一个私有变量)。#task-template您可以渲染listLocal并且它将保持react性(即,如果parentList更改它将更新Task组件)。您还可以listLocal通过调用 setter(例如this.listLocal = newList)来改变它,它会将更改发送给父级。

这种模式的优点在于您可以传递listLocalTask(using v-model) 的子组件,并且来自子组件的更改将传播到顶级组件。

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

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

如果EditTask发出改变它会适当地调用set()listLocal,并由此传播事件到顶层。类似地,EditTask组件也可以使用 调用其他子组件(例如表单元素)v-model

我认为这是向父组件发出更改的更轻松的方式。
2021-03-17 01:41:14
除了同步之外,我正在做类似的事情。问题是我需要在发出我的更改事件后运行另一个方法,但是当该方法运行并命中 getter 时,我得到旧值,因为更改事件尚未被侦听器接收/传播回子级。在这种情况下,我想改变 prop 以便我的本地数据是正确的,直到父更新向下传播。在这方面有什么想法吗?
2021-03-18 01:41:14
道具下降和事件上升是我点击的原因。这在 VueJs 的文档中在哪里解释?
2021-03-29 01:41:14
我怀疑从 setter 调用 getter 不是一个好习惯。您可能会考虑在您的计算属性上放置一个监视并在那里添加您的逻辑。
2021-03-31 01:41:14
2021-04-11 01:41:14

Vue 只是警告您:您更改了组件中的 prop,但是当父组件重新渲染时,“列表”将被覆盖,您将丢失所有更改。所以这样做是很危险的。

像这样使用计算属性:

Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    computed: {
        listJson: function(){
            return JSON.parse(this.list);
        }
    }
});
2 路绑定道具怎么样?
2021-03-12 01:41:14
如果你想要 2 路数据绑定,你应该使用自定义事件,更多信息阅读:vuejs.org/v2/guide/components.html#sync-Modifier你仍然不能直接修改 prop,你需要一个事件和函数为您处理道具更改。
2021-04-03 01:41:14

如果你使用 Lodash,你可以在返回它之前克隆 prop。如果您在父级和子级上修改该props,则此模式很有用。

假设我们在组件grid有 prop列表

在父组件中

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

props下降,事件上升。这就是 Vue 的模式。关键是,如果你试图改变从父级传递过来的 props。它不起作用,它只会被父组件反复覆盖。子组件只能发出一个事件来通知父组件做某事。如果你不喜欢这些限制,你可以使用 VUEX(实际上这种模式会吸收复杂的组件结构,你应该使用 VUEX!)

vue 3 本身不支持事件总线。github.com/vuejs/rfcs/pull/118
2021-03-25 01:41:14
还有一个选项可以使用事件总线
2021-03-30 01:41:14