【问题标题】:VueJS error Avoid mutating a prop directlyVueJS错误避免直接改变道具
【发布时间】:2018-08-25 05:03:12
【问题描述】:

我正在尝试创建一个模式,但只有在我关闭它时才会出现此错误:

[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: "value"

found in

---> <PanelDesconectarModal> at resources\assets\vue\PanelDesconectarModal.vue
       <VNavigationDrawer>
         <PanelDrawer> at resources\assets\vue\PanelDrawer.vue
           <VApp>
             <PanelRoot> at resources\assets\vue\PanelRoot.vue
               <VApp>
                 <Root>

PanelDesconectarModal.vue

<template>
    <v-dialog v-model="value" max-width="350">
        <v-card :dark="($theme === 'dark')">
            <v-card-title class="headline">Desconectar</v-card-title>
            <v-divider></v-divider>
            <v-card-text>Você tem certeza que deseja desconectar-se?</v-card-text>
            <v-card-actions>
                <v-spacer></v-spacer>
                <v-btn flat @click.native="closeDialog">Cancelar</v-btn>
                <v-btn :color="$color" flat="flat" @click.native="desconectar">Desconectar</v-btn>
            </v-card-actions>
        </v-card>
    </v-dialog>
</template>

<script>
    export default {
        name: 'panel-desconectar-modal',
        props: ['value'],
        methods: {
            closeDialog() {
                this.value = false;
            },
            desconectar() {
                this.closeDialog();

                window.location = this.$route + '/panel/desconectar';
            }
        }
    }
</script>

使用 ProgressDesconectarModal.vue,showDesconectar 是一个数据变量

<panel-desconectar-modal :value="showDesconectar"></panel-desconectar-modal>

【问题讨论】:

  • 我已经answered了类似的问题,但由于某种原因OP没有投票,所以无法链接。

标签: vue.js vuejs2 vuetify.js


【解决方案1】:

发生这种情况是因为您的 v-model 中有道具 value

不要那样做,因为当v-model 更改时,这会改变prop(value)(你应该只用v-model afaik 更改data 值,但在这种情况下,你甚至不需要额外的data 变量)。

由于vuejs v2.3.0, it is suggested to emit value to the parent,所以父组件改变它,然后传递给子组件。


所以你所要做的就是:

v-dialog 组件中

删除 v-model 并将其替换为 :value="value" @input="$emit('input')"

还有你的功能:

closeDialog() {
    this.$emit('input');
}

panel-desconectar-modal 组件中使用v-model="showDesconectar"


这将工作because

<input v-model="something"> is syntactic sugar for:

<input   
    v-bind:value="something"
    v-on:input="something = $event.target.value">

这是我在answersimilar question 中提供的working example pen

【讨论】:

  • 非常感谢,我还在学习VueJS,还没有掌握
  • 我发现使用v-dialog最好有@input="$emit('input', $event)",这样当对话框关闭时父值将设置为false而不是undefined
【解决方案2】:

您不应该改变子组件中的道具。您只能改变对象,但不能改变基元。因此,您可以使用数据选项或计算属性:

data() {
  return {
    childValue: this.value; // initialize props value
  }
}

现在,您可以更改childValue

closeDialog() {
   this.childValue = false;
},

确保在子组件中的任何地方都使用childValue,而不是value props。

【讨论】:

  • 我觉得不用data,看我的answer
【解决方案3】:

这真的是问自己的时刻“我真的需要一个道具吗?我可以用数据做这个吗?我在这里是因为我错误地在 Vue 组件中放置了一些状态吗?”

如果你是页面和组件的作者,并且组件只在页面上出现一次,那么没有很好的理由使用 props。 如果你需要 props,因为组件是对数组中的所有行重复,使道具只是数组索引,因此组件可以直接修改存储中的源数组。 Vue 组件不应该包含状态,尤其是需要共享的状态,并且不喜欢彼此紧密绑定。父子关系源于它们在 DOM 树中的放置机会,(子代出现在父代的标记内)。这就像在夜总会里的一次偶然相遇。孩子可能与父母没有任何关系。您的源数据的层次结构应该独立于您的标记,在您的商店结构中表达。您的 Vue 组件应尽可能与 store 建立密切的双向关系,并且彼此之间不怎么交流 :-)

【讨论】:

  • 但是,在 OP 的情况下,可以像我建议的那样使用 v-model。是的,v-model 暗示 prop,但很可能父组件将需要该数据(即showDesconectar),因为在父组件中很可能有一个打开模式的按钮(因此需要共享状态,我猜只有在这两个组件之间?)。我想知道您是否认为这是一种“不好的做法”,是否有任何工作示例可以显示一些替代方案?我不太明白你的意思(如果你暗示 OP 正在做的事情就是不好的做法),所以我很乐意看看你会怎么做。
  • 我们目前使用返回承诺的方法调用来攻击我们的模态对话框组件。语法很好,但这意味着对话框的状态是no longer in the store。我喜欢你的回答。为什么我们应该只将 v-model 用于表单输入。当事件由 Vue 组件发出时,$event.target 是什么。我需要摆弄这个!
  • > What is $event.target when the event is emitted by a Vue component. - 请注意,这是专门的 vuetify.js 组件,所以我的猜测是它取决于自定义组件、它发出的事件以及何时发出。
  • 是的。该示例有效,因为对话框设置为“”且“”为假。
  • 再想一想:Your Vue components, where possible, should have an intimate two way relationship with the store, and not talk much to each other-afaik 每个组件都可以与商店通信,因此您实际上是在说->“组件根本不应该直接相互通信”。所以我不同意这一点。我喜欢你的观点,即组件应该通过 store 相互通信,但在这个非常简单的父子案例中,这可能是一种矫枉过正并且可能会造成混淆的观点。
【解决方案4】:

relevant Vue doc 中没有默认值的示例,因此这些答案可以在其他地方找到。我需要一个解决方案来创建一个具有默认值的组件,但是当它失去焦点时,输入总是会弹回到它之前的状态,或者它给出了“避免直接改变一个道具”错误。创建一个可变属性并在created 事件中设置它的值为我解决了这个问题:

data()
{
    return {
        text: null
    };
},

props: {
    properties: Object,
    value: String
},

created()
{
    this.text = this.value;
}

【讨论】:

    猜你喜欢
    • 2020-06-23
    • 2019-02-07
    • 2021-06-18
    • 2019-11-07
    • 2019-09-11
    • 1970-01-01
    • 2021-06-08
    • 2018-03-05
    • 2020-04-03
    相关资源
    最近更新 更多