避免直接改变道具 - Datatable VueJS

Posted

技术标签:

【中文标题】避免直接改变道具 - Datatable VueJS【英文标题】:Avoid mutating a prop directly - Datatable VueJS 【发布时间】:2020-06-23 17:16:09 【问题描述】:

我是 Vue JS 的新手,我遇到了这个问题我尝试通过将父道具传递给孩子来制作数据表

我收到此错误

[Vue 警告]:避免直接改变 prop,因为每当父组件重新渲染时,该值都会被覆盖。相反,使用基于道具值的数据或计算属性。正在变异的道具:“editedItem”


这是我的代码

这是我的主页:

<template >
  <v-container  >

    <v-col>
     <Datatables
      :headers="this.headers"
      :items="items"
      :editedItem="this.editedItem"
      :defaultItem="defaultItem"
      sort-by="calories"
      class="elevation-1" />
    </v-col>
  <v-spacer></v-spacer>
  <br>
    <v-col>

    </v-col>
  </v-container >
</template>

<script>

import Datatables from '../../components/Datatable/CrudDatatable'
export default 

  components:

    Datatables

  ,
  data() 
   return 

      headers: [
        
          text: 'Dessert (100g serving)',
          align: 'start',
          sortable: false,
          value: 'name',
        ,
         text: 'Calories', value: 'calories' ,
         text: 'Fat (g)', value: 'fat' ,
         text: 'Carbs (g)', value: 'carbs' ,
         text: 'Protein (g)', value: 'protein' ,
         text: 'Actions', value: 'action', sortable: false ,
      ],
      items: [],
      editedItem: 
        name: '',
        calories: 0,
        fat: 0,
        carbs: 0,
        protein: 0,
      ,
      defaultItem: 
        name: '',
        calories: 0,
        fat: 0,
        carbs: 0,
        protein: 0,
      ,


   
 ,
  created () 
      this.initialize()
    ,
    methods: 
       initialize () 
        this.items = [
          
            name: 'Frozen Yogurt',
            calories: 159,
            fat: 6.0,
            carbs: 24,
            protein: 4.0,
          ,
          
            name: 'Ice cream sandwich',
            calories: 237,
            fat: 9.0,
            carbs: 37,
            protein: 4.3,
          ,
        ]
      ,



    ,






</script>


<style>

</style>


这是我的组件:

<template>
  <v-data-table :headers="headers" :items="items" sort-by="calories" class="elevation-1">
    <template v-slot:top>
      <v-toolbar flat color="white">
        <v-toolbar-title>My CRUD</v-toolbar-title>
        <v-divider class="mx-4" inset vertical></v-divider>
        <v-spacer></v-spacer>
        <v-dialog v-model="dialog" max->
          <template v-slot:activator=" on ">
            <v-btn color="primary" dark class="mb-2" v-on="on">New Item</v-btn>
          </template>
          <v-card>
            <v-card-title>
              <span class="headline"> formTitle </span>
            </v-card-title>

            <v-card-text>
              <v-container>
                <v-row>
                  <v-col cols="12" sm="6" md="4">
                    <v-text-field v-model="editedItem.name" label="Dessert name"></v-text-field>
                  </v-col>
                  <v-col cols="12" sm="6" md="4">
                    <v-text-field v-model="editedItem.calories" label="Calories"></v-text-field>
                  </v-col>
                  <v-col cols="12" sm="6" md="4">
                    <v-text-field v-model="editedItem.fat" label="Fat (g)"></v-text-field>
                  </v-col>
                  <v-col cols="12" sm="6" md="4">
                    <v-text-field v-model="editedItem.carbs" label="Carbs (g)"></v-text-field>
                  </v-col>
                  <v-col cols="12" sm="6" md="4">
                    <v-text-field v-model="editedItem.protein" label="Protein (g)"></v-text-field>
                  </v-col>
                </v-row>
              </v-container>
            </v-card-text>

            <v-card-actions>
              <v-spacer></v-spacer>
              <v-btn color="blue darken-1" text @click="close">Cancel</v-btn>
              <v-btn color="blue darken-1" text @click="save">Save</v-btn>
            </v-card-actions>
          </v-card>
        </v-dialog>
      </v-toolbar>
    </template>
    <template v-slot:item.action=" item ">
      <v-icon small class="mr-2" @click="editItem(item)">mdi-pencil</v-icon>
      <v-icon small @click="deleteItem(item)">mdi-delete</v-icon>
    </template>
    <template v-slot:no-data>
      <v-btn color="primary" @click="initialize">Reset</v-btn>
    </template>
  </v-data-table>
</template>
<script>
export default 
  props: 
    headers: 
      type: Array
    ,
    items: 
      type: Array
    ,
    editedItem: 
      type: Object
    ,
    defaultItem: 
      type: Object
    
  ,
  data: () => (
    dialog: false,
    editedIndex: -1,
  ),

  computed: 
    formTitle() 
      return this.editedIndex === -1 ? "New Item" : "Edit Item";
    
  ,

  watch: 
    dialog(val) 
      val || this.close();
    
  ,
  created () 
      this.getParentItem()
    ,
  methods: 

    getParentItem()



    ,

    editItem(item) 
      this.editedIndex = this.items.indexOf(item);
      this.editedItem = Object.assign(, item);
      this.dialog = true;
    ,

    deleteItem(item) 
      const index = this.items.indexOf(item);
      confirm("Are you sure you want to delete this item?") &&
        this.items.splice(index, 1);
    ,

    close() 
      this.dialog = false;
      setTimeout(() => 
        this.editedItem = Object.assign(, this.defaultItem);
        this.editedIndex = -1;
      , 300);
    ,

    save() 
      if (this.editedIndex > -1) 
        Object.assign(this.items[this.editedIndex], this.editedItem);
       else 
        this.items.push(this.editedItem);
      
      this.close();
    
  
;
</script>



【问题讨论】:

【参考方案1】:

在组件的created 中添加一些设置为 prop 变量的数据变量。喜欢:

this.internalItems = this.items
this.internalEditedItem = this.editedItem

然后在你的方法中编辑那些而不是 prop 变量。

this.internalEditedItem = Object.assign(, item);
...
Object.assign(this.items[this.editedIndex], this.internalEditedItem);
...etc

如果您打算从父级修改道具,您还需要添加一个监视变量以将它们重置为新值。

【讨论】:

我又遇到了同样的错误,或者我做错了什么,请帮忙....我为此努力了 gist.github.com/panudet-24mb/f3ca188adc45dacfed4883017c8a98ee 我没有时间看你所有的代码,但是这个错误可以通过这样的方式解决。检查每个 prop 以查看是否在方法中对其进行了修改,如果是,则添加一个新的数据变量并使用它来代替 prop

以上是关于避免直接改变道具 - Datatable VueJS的主要内容,如果未能解决你的问题,请参考以下文章

Vue关闭组件返回避免直接改变道具

避免直接改变道具(渲染功能)

避免直接改变道具,因为该值将被覆盖

避免在 Nuxt VueJs 中直接改变道具

避免直接改变道具,因为每当父组件重新渲染时,该值都会被覆盖

Vue:props 不会自动分配;手动分配时 - 避免直接改变道具 - 错误