Home > Mobile >  Vue js Avoid mutating a prop directly since the value will be overwritten
Vue js Avoid mutating a prop directly since the value will be overwritten

Time:11-03

I am trying to make my vue component as flexible as possibile, So i have some button and a search i need to use on all my table component . For now it is hard coded, but i wnat to make it more flexible, everything work until now except the search . I see an error like this on console

ERROR: [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: "query"

I know the problem is when i try to change the query input but does now know how to fix this problem. Does anyone know ?

//custom action buttons
import Button from './button.js';

export default {
    components: {
        'v-button': Button
    },

    props: {
        query: {
          type: String
        },
        selected: {
            type: Array
        },
        url: {
            type: String
        }
    },

    // props: [
    //     'selected',
    //     'query',
    //     'url'
    // ],

    methods: {
        showModal() {
            this.$emit('showModal')
        },

        massDeleteRecord() {
            this.$emit('massDeleteRecord')
        }
    },

    template: `
        <div >
            <div >
                <div >
                    <v-button type="success" @click.prevent="showModal" >
                        Add Record
                    </v-button>
                    <v-button type="primary" data-mdb-toggle="collapse" data-mdb-target="#collapseFilter" aria-expanded="false" aria-controls="collapseFilter" >
                        Filter
                        <i ></i>
                    </v-button>
                    <v-button v-show="selected.length>0" type="danger"  id="dropdownMenuButton" data-mdb-toggle="dropdown" aria-expanded="false" >
                            Action ({{selected.length}})
                    </v-button>
                    <ul  aria-labelledby="dropdownMenuButton">
                        <li>
                            <a :href="url" >
                                Export
                                <i ></i>
                            </a>
                        </li>
                        <li>
                            <v-button @click="massDeleteRecord()" type="danger" >
                                Delete
                                <i ></i>
                            </v-button>
                        </li>
                    </ul>
                </div>
                <div >
                    <input @input="$emit('updatedQuery', $event.target.value)" 
                        :value="query"
                        type="search"
                        
                        placeholder="Search"
                    />
                </div>
            </div>
            
        </div>
    `,
}

User Table Component

<template>
<table-custom-action 
   @massDeleteRecord="massDeleteUser" 
   @showModal="showModal" 
   @updated-query="(newQuery) => query = newQuery"
   :selected="selected"
   :query="query"
   :url="url"
 ></table-custom-action>
</template>

<script>
import TableCustomAction from './partials/modules/TableCustomAction.js';
export default {
        components: {
            TableCustomAction,
        },
        
        data(){
            return {
                ....
                query: '',
                ....
                url: ''
            }
        },  
watch: {
            query: function(newQ, old) {
                if (newQ === "") {
                    this.getRecord();
                } else {
                    this.searchRecord();
                }
            },
        },
</script>

CodePudding user response:

Rather than using v-model on query, send back the update to the parent. It will update in the parent, be transferred through the props to your child and produce the same result. If you mutate it in the child, then it will at some point mutate in the parent, hence do twice the work.
Here is a nice article on the subject.


Also, you don't update props actually, they are read-only.

In the child

<input @input="$emit('updatedQuery', $event.target.value)" 
  :value="query"
  type="search"
  
  placeholder="Search"
/>

In the parent

<table-custom-action @updated-query="(newQuery) => query = newQuery">
</table-custom-action>

UPDATE: here is a working repro.


More details here in the doc.

  • Related