【问题标题】:use a data or computed property based on the prop's value. Prop being mutated根据道具的值使用数据或计算属性。道具被变异
【发布时间】:2021-09-30 06:00:45
【问题描述】:

我在 vue 中打开了一个模态,但我从导航器的控制台中收到了下一个错误:

避免直接改变prop,因为值会被覆盖 每当父组件重新渲染时。相反,使用数据或 基于道具值的计算属性。道具被变异: “表演任务”

它说我应该使用计算属性,并且我已经检查了其他解决方案,但是它们中的任何一个都可以解决它,因为我使用的是打字稿,在这种特殊情况下如何使用计算属性来解决它?

在这种情况下,它指的是模态到我的子组件,模态:

<template>
  <v-row justify="space-around">
    <v-col cols="auto">
      <v-dialog
        transition="dialog-bottom-transition"
        v-model="showTask"
        max-width="600"
      >
        <template>
          <!--  -->
          <v-card class="p-5">
            <v-row>
              <v-col cols="12" sm="8">
                <h1 class="is-size-4">Miembros del equipo</h1>
              </v-col>
              <v-col class="d-flex justify-end" cols="12" sm="4">
                <v-btn icon>
                  <v-icon aize="10" @click="showTask = false"
                    >fas fa-close</v-icon
                  >
                </v-btn>
              </v-col>
            </v-row>
            <v-form ref="form" lazy-validation>
              <!-- Autocomplete de usuarios -->
              <!-- nota: "Autocomplete recibe solamente un valor del objeto que se le pasa, en este caso se declara con item-value="id" -->
              <v-autocomplete
                v-model="UsersIn"
                :items="users"
                item-text="name"
                item-value="id"
                :disabled="isUpdating"
                chips
                filled
                label="Agregar Miembros"
                persistent-hint
                 multiple
              >
                <template v-slot:selection="data">
                  <!-- Chips dentro del field -->
                  <v-chip
                    v-bind="data.attrs"
                    :input-value="data.selected"
                    close
                    @click="data.select"
                    @click:close="remove(data.item)"
                  >
                    <v-avatar left>
                      <v-img :src="data.item.Photo"></v-img>
                    </v-avatar>
                    {{ data.item.name }}
                  </v-chip>
                </template>
                <template v-slot:item="data">
                  <template>
                    <v-list-item-avatar>
                      <v-avatar color="red">
                        <img :src="data.item.Photo">
                      </v-avatar>
                    </v-list-item-avatar>
                    <v-list-item-content>
                      <v-list-item-title
                        v-html="data.item.name"
                      ></v-list-item-title>
                      <v-list-item-subtitle
                        v-html="data.item.group"
                      ></v-list-item-subtitle>
                    </v-list-item-content>
                  </template>
                </template>
              </v-autocomplete>
            </v-form>
            <!-- Iconos -->
          </v-card>
        </template>
      </v-dialog>
    </v-col>
  </v-row>
</template>

<script lang="ts">
export default {
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
  data: () => {
     const srcs = {
        1: 'https://cdn.vuetifyjs.com/images/lists/1.jpg',
        2: 'https://cdn.vuetifyjs.com/images/lists/2.jpg',
        3: 'https://cdn.vuetifyjs.com/images/lists/3.jpg',
        4: 'https://cdn.vuetifyjs.com/images/lists/4.jpg',
        5: 'https://cdn.vuetifyjs.com/images/lists/5.jpg',
      }
    return {
      autoUpdate: true,
      friends: ['Sandra Adams', 'Britta Holt'],
      isUpdating: false,
      name: 'Midnight Crew',
      UsersIn: [{}],
      headers: [
        {
          align: 'start',
          sortable: false,
          value: 'name',
        },
        { text: '', value: 'photo' },
        { text: '', value: 'name' },
      ],
      title: 'The summer breeze',
      users: [
        {
          initials: 'CA',
          Photo: srcs[1],
          name: 'Carlos',
          id: 2
        },
        {
          Photo: srcs[2],
          name: 'Luther',
          initials: 'Lu',
          id: 1
        },
          {
          Photo: srcs[3],
          name: 'Lutherino',
          initials: 'Lu',
          id: 3
        },
      ],
    }
  },
 watch: {
      isUpdating (val: boolean): void {
        if (val) {
          setTimeout(() => (this.isUpdating = false), 3000)
        }
      },
    },
  props: {
    showTask: {
      type: Boolean,
      default: false,
    },
  },
  methods: {
    remove (user: any) {
        var index = this.UsersIn.indexOf(user.id)
        if (index >= 0) this.UsersIn.splice(index, 1)
      },
  },
}
</script>

我正在使用这种方法将“showTask”状态更改为我的父组件:

 <add-members-modal :showTask.sync="ShowModal"></add-members-modal>

 <v-btn color="#fff" elevation="0" @click="showModal"
      ><v-icon color="#000A21" class="mx-1" size="18"
        >fas fa-user-plus</v-icon
      >Añadir / 1</v-btn
    >

<script lang="ts">
       methods: {
        showModal (): void {
          this.ShowModal = false
          this.ShowModal = true
        }
</script>

【问题讨论】:

  • @click="showTask = false" 那是你直接改变道具的地方,因为警告/错误告诉你要避免
  • @Bravo 但如果我将 @click="showTask = false" 放在父组件中,我将如何打开模式?在这种情况下,我将表明它是错误的,并且孩子不会打开对话框
  • 你不会把它放在父级中,这没有任何意义......你想向父级发出一个事件,以便它可以改变 showTask 的值
  • 顺便说一句-你的showModal方法完全错误-它总是设置this.ShowModal = true

标签: javascript vue.js


【解决方案1】:

为避免此错误,您可以使用 Vuejs 的双向绑定概念。 您可以在其中将父组件的 showTask 变量绑定到您的子组件中。

可以关注这篇文章,这篇文章就是基于这个问题写的。

Two way binding of dialogs in Vuejs

【讨论】:

  • 它对我有用,但是当用户在外面点击时,我在对话框中添加了 '@click:outside = "$emit('close')"',非常感谢跨度>
  • 只有外部内容链接的答案不被认为是好的答案 - 为什么不在您的答案中加入最少的代码来演示解决方案
  • 是的,如果将来由于某种原因链接不再可用,这可能是最好的
  • 是的,您是对的,但此链接将可用,因为这是一篇中型文章,我拥有此中型帐户。 @Bravo 谢谢!
猜你喜欢
  • 2021-09-02
  • 2019-12-08
  • 2020-12-14
  • 2017-10-13
  • 1970-01-01
  • 2021-03-04
  • 2018-02-07
  • 1970-01-01
  • 2017-11-23
相关资源
最近更新 更多