【问题标题】:Trying to avoid mutating a prop that goes 3 levels deep by using $emit试图通过使用 $emit 来避免改变 3 级深度的道具
【发布时间】:2021-07-21 21:16:34
【问题描述】:

编辑:Here's a repo 我是为了更容易解析。

我有一个在数据表中列出产品的组件。表格的第一列是一个链接,显示一个带有被点击产品形式的模式(使用其 ID)。我正在使用 PrimeVue 库进行样式和组件。

<template>
   <Column field="id" headerStyle="width: 5%">
     <template #body="slotProps">
        <ProductForm :product="slotProps.data" :show="showModal(slotProps.data.id)" />
           <a href="#" @click.stop="toggleModal(slotProps.data.id)">
              <span class="pi pi-external-link"> </span>
           </a>
     </template>
   </Column>
</template>

<script>
import ProductForm from "./forms/ProductForm";

export default {
  data() {
     return {
       activeModal: 0,
     }
  },
  components: { ProductForm },
  methods: {
    toggleModal: function (id) {
      if (this.activeModal !== 0) {
        this.activeModal = 0;
        return false;
      }
      this.activeModal = id;
    },
    showModal: function (id) {
      return this.activeModal === id;
    },
  },
</script>

模态实际上是 ProductForm 组件的一个子组件(我制作了一个模态的模板以便我可以重用它)。所以它是 3 个组件(ProductList -> ProductForm -> BaseModal)。这是产品形式:

<template>
  <div>
    <BaseModal :show="show" :header="product.name">
      <span class="p-float-label">
        <InputText id="name" type="text" :value="product.name" />
        <label for="name">Product</label>
      </span>
    </BaseModal>
  </div>
</template>

<script>
import BaseModal from "../_modals/BaseModal";

export default {
  props: ["product", "show"],
  components: { BaseModal },
  data() {
    return {};
  },
};
</script>

当模式弹出时,它使用 ProductForm 子组件。这是 BaseModal 组件:

<template>
  <div>
    <Dialog :header="header" :visible.sync="show" :modal="true" :closable="true" @hide="doit">
      <slot />
    </Dialog>
  </div>
</template>

<script>
export default {
  props: {
    show: Boolean,
    header: String,
  },
  methods: {
    doit: function () {
      let currentShow = this.show;
      this.$emit("showModel", currentShow)
    },
  },
  data() {
    return {
    };
  },
};
</script>

我传递了product 对象和一个show 布尔值,它指定模态是否从第一个组件(ProductList)一直到ProductForm 组件,最后到BaseModal 组件可见或不可见。模态是PrimeVue component called Dialog。该组件实际上有它自己的名为“可关闭”的属性,它在单击时使用 X 按钮关闭模式,它与名为 hide 的事件相关联。一切实际上都有效。我可以打开模式并关闭它。出于某种原因,我必须单击另一个模态链接两次才能在初始链接之后打开。

问题是当我关闭一个模式时,我收到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: "show" 错误。我已经尝试了所有方法来向事件发出并更改那里的原始道具值,但错误仍然存​​在(即使来自上面的代码)但我不确定是否因为我有 3 个组件深它不会工作。我对使用道具和插槽以及 $emit 很陌生,所以我知道我做错了什么。我对将组件布局这么深也是新手,所以我什至可能没有正确地完成整个布局。我错过了什么?

【问题讨论】:

    标签: javascript vue.js vuejs2 modal-dialog primevue


    【解决方案1】:

    好吧,您正在从BaseModal 发出showModel 事件,但您没有在父母上收听它并转发它+在祖父母上收听(ProductForm

    但主要问题是BaseModal 中的:visible.sync="show"。就像你做:visible="show" @update:visible="show = $event" (docs) 一样。因此,当 Dialog 关闭时,PrimeVue 会发出 update:visible 事件,该事件由 BaseModal 组件选择(感谢 .sync 修饰符)并导致 BaseModal 内的 show 属性发生突变和错误消息...

    切记永远不要将 prop 值直接与 v-model.sync 一起使用

    要修复它,请通过 computed with the setter 间接使用道具:

    BaseModal

    <template>
      <div>
        <Dialog :header="header" :visible.sync="computedVisible" :modal="true" :closable="true">
          <slot />
        </Dialog>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        show: Boolean,
        header: String,
      },
      computed: {
        computedVisible: {
          get() { return this.show },
          set(value) { this.$emit('update:show', value) }
        }
      },
    };
    </script>
    

    现在您可以将相同的计算添加到您的ProductForm 组件中并将模板更改为&lt;BaseModal :show.sync="computedVisible" :header="product.name"&gt;(因此当ProductForm 接收到update:show 事件时,它将向其父级发出相同的事件 - 这是必需的Vue 事件不会像 DOM 事件那样“冒泡”,只有直接父组件接收事件)

    最后一步是处理ProductList中的update:show&lt;ProductForm :product="slotProps.data" :show="showModal(slotProps.data.id)" @update:show="toggleModal(slotProps.data.id)"/&gt;

    【讨论】:

    • 非常感谢。我即将着手解决这个问题(不想让你认为我阅读了你的评论并且不欣赏它)。我对使用道具并将它们寄回给父母/祖父母非常陌生。你解释得很好。谢谢!
    • 效果很好!就这样我明白了......要将道具从 BaseModal 一直带到它的祖父母,我需要在沿途的每个组件中添加和 $emit 计算属性?
    猜你喜欢
    • 2019-11-07
    • 1970-01-01
    • 2022-06-16
    • 2020-06-23
    • 2020-12-23
    • 1970-01-01
    • 1970-01-01
    • 2018-03-05
    • 2019-02-07
    相关资源
    最近更新 更多