Vue: Silence Prop Mutation Warning.

Created on 24 Jan 2018  路  5Comments  路  Source: vuejs/vue

What problem does this feature solve?

In my case I am using vuetable-2, I am pulling in the Vuetable component as a mixin and that is fine, I can use the prop defaults to define what I want the defaults to be and I can even use cssmodules on vuetable without modifying the template.

The problem comes in when using a prop that no matter what the parent has, needs to be transformed before being passed to the template. Using a component as a mixin is a good technique to override defaults in third party components but the only way to transform a prop before passing it to the template is mutating the prop since you cannot use the technique in the docs (creating a separate data or computed attribute) as if you want to avoid modifying the template, you have to keep the name the same.

I did come up with a reasonable workaround but it triggers the warning of mutating the prop. It works but in this case the technique I used makes the warning more or less obsolete so I would like to disable it.

Here is an example of the technique, using my vuetable override:

<script>
    import Vuetable from 'vuetable-2/src/components/Vuetable'

    export default {
        mixins: [Vuetable],
        props: {
            noDataText: {
                type: String,
                default() {
                    return 'No Data Available'
                }
            },
            noDataTemplate: {
                type: String,
                default() {
                    return 'No Data Available'
                }
            }
        },
        mounted() {
            this.noDataTemplate = '<div class="'   this.$style.empty   '">'   this.noDataText   '</div>'
        }
    }
</script>

What is happening is I am effectively using a different prop for the parent to use, then mutating the prop that now should not be used by any parent. It has effectively become a data attribute that because I am using a mixin must remain a prop. To me this means that there should be no danger of the child mutating the parents state that the warning is trying to cover.

What does the proposed API look like?

What I am thinking is simply just another option in props, there is currently type and default and another one could be added. I am thinking something like private. By default props are public because the parent can mutate the state but what private does is turn it into a data attribute that lives under props.

The main use of this is that overwriting a component can change it to true, and then use the prop as a data attribute without triggering the warning. To help make sure it does not cause people to just add that to mutate the state without the warning and without proper handling of it, a warning can be added if the component uses it as a prop like normal. Something like Prop set as private indicating the child is handling the props state, editing the state from the parent will mutate the childs state (basically just a reversal of the current warning).

props: {
   noDataTemplate: {
      type: String,
      private: true,
      default() {
           return 'something'
       }
   }
}

All 5 comments

Props are meant to be read-only, being able to suppress the warning will be acknowledging that it is sometimes acceptable to do otherwise.
What you may want to do is wrap the Vuetable component (best option), contact the author, send a pull request or create your own fork.

To wrap the component you can use a template or but sometimes a render function may make things easier

export default {
    render (h) {
        return h(Vuetable, {
            props: {
                // you can customise how props are passed
                // more at https://vuejs.org/v2/guide/render-function.html#createElement-Arguments
            }
        }
}

The component is wrapped (via mixin), the issue stems from not wanting to edit the template, as such editing the template to use a different prop name won't work.

I understand the idea of them being read only and this actually conforms to it, as all its doing is on render defining the prop based on another prop. However in the default you cannot use another prop as it has not been initialized, this just moves setting the default a little further down the lifecycle.

Using the private key is only my own idea of a solution, but effectively anything that lets you set the default later in the lifecycle without triggering the warning will cover the use case.

I tried making a pull request but got lost in the code for the lifecycle witch is where I decided to make an issue to open up a discussion first. I will keep thinking on it and may open another issue or pull request (as an example for discussion) if I can manage to add it myself.

I was talking about a pull request on vuetable, not Vue.
Wrapping a component cannot be done via a mixin. Wrapping is the code I showed above or, in a template:

// MyVuetable.vue
<template>
    <Vuetable :a-prop="override"/>
</template>

<script>
import Vuetable from 'vuetable'

export default {
  props {
    // reuse Vuetable props
    ...Vuetable.props
    }   
}

I guess using the example with Vuetable was a bad idea, Its not really related to the problem, so there is nothing I could add to a pull request that helps here.

I do also wrap it as you described as well, the issue is that when you want to adjust styles and such, especially in my case using css modules (I don't think it would also happen for scoped css though), It needs to be in the context of the active component, not the parent. This brings up an interesting but easy to get around issue of needing to override the component, while keeping the template intact.

You can see in my example in my first message that I am wrapping the prop with a div that passes a css module class to it., normally I would think I can just override the prop from vuetable and set the default with it in there (since Its read-only), but then it will not see my other prop within the default function.

I mean at the end of the day all I am looking to do is suppress the warning on dev when you set the default prop value at a point that the values of other props are available to be used with it (to defer the prop until the other props are set?).

I have something like this which comes in handy in triggering the error state or clearing it off of forms.

/**
 * Sets the error state to valid for any vuetify component inheriting from
 * https://github.com/vuetifyjs/vuetify/blob/dev/src/mixins/validatable.js
 *
 * @param {Validatable} elementReference Validatable component
 */
function clearErrorForValidatable(elementReference) {
  if (elementReference) {
    elementReference.error = false;
    elementReference.rules = [];
    elementReference.rules[0] = true;
    if (typeof elementReference.validate === 'function') {
      elementReference.validate();
    }
  }
}

I get a warning saying that the value will be overridden once the component renders again. That is exactly the behaviour I want, as the form is supposed to reset once it re-renders. How may I suppress the warning?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

robertleeplummerjr picture robertleeplummerjr  路  3Comments

fergaldoyle picture fergaldoyle  路  3Comments

gkiely picture gkiely  路  3Comments

bdedardel picture bdedardel  路  3Comments

seemsindie picture seemsindie  路  3Comments