Ondřej Želazko
Ondřej Želazko

Reputation: 659

Vue.js component custom non-reactive properties safe name

  1. What is a safe naming for custom properties for component instance?
  2. What is the recommended way to store component-specific but non-reactive data?

some reasoning:

While working with Vue.js, from time to time end up in a situation which I need to store some static data within the component instance. As far as I understand Vue, a component instance can be considered as a plain object with some special attributes (this.$data, .$el, .$parent, etc.). That tells me that I can do whatever I want with the object, only be aware not collide with internally used attribute names.

A common example of this is a Web Component Element that holds some other logic or even shadow DOM (e.g. Canvas for WebGl) and the reference is bound to the Vue component, meaning there's some init logic and dispose logic bound to component's lifecycle. The reference here can be a proxy object, not necessarily the DOM element itself. I usually store it in the component as a direct property with "_" prefix:

<template>
  <my-custom-canvas @ready="canvasReady">
</template>
<script>
export default {
  methods: {
    canvasReady (canvas) { this._my_custom_canvas = canvas; }
  }
}
</script>

so ad 1. is it "ok-ish" and "safe" to pollute the component instance like this? Or should I put this into the this.$data, making it reactive data though? And ad 2. ultimately, I can't find any good guides on how to work with non-reactive data in Vue. There are cases where it feels like it should be contained in the component itself, not somewhere outside in global space. Also, is it just plain wrong or is it an edge case where there are no conventions? Could anybody give me some arguments why I should avoid custom non-reactive attributes?

Upvotes: 0

Views: 543

Answers (2)

skirtle
skirtle

Reputation: 29092

I wouldn't necessarily call it a duplicate but you may find the answers to this question relevant:

How to set a component non-reactive data in Vue 2?

This topic has also been discussed by the Vue core team:

https://github.com/vuejs/vue/issues/1988

The short answer is there's nothing wrong with adding non-reactive data directly to this.

Vue uses _ and $ prefixes for its own internal properties (see here https://v2.vuejs.org/v2/api/#data) so you may find that avoiding those prefixes is actually safer. From a name collision perspective it's really no different to when you're naming your props, data properties etc. as they also get exposed through properties of this. Private properties of mixins, etc. have their own convention, outlined in https://v2.vuejs.org/v2/style-guide/#Private-property-names-essential. If nothing else I recommend reading the Detailed Explanation section as that further discusses Vue's own naming conventions.

On a somewhat related note, if you freeze an object using Object.freeze then Vue won't attempt to make it reactive. This isn't really relevant to the case where the object is an HTML element but if you're just trying to keep large, static data away from the reactivity system then this can be an easier way.

Upvotes: 1

Daniel
Daniel

Reputation: 35684

When I need to store non-reactive data, such as consts or enums, I just put it into the data object outside of the data function, and into the created lifecycle method.

When you define a variable on data outside of the data function, they are not going to be reactive.

for example, this would initialize it as a null value, and make it available in the template if needed, but if it changes, it won't initiate a refresh.

<template>
  <my-custom-canvas @ready="canvasReady">
</template>
<script>
export default {
  methods: {
    canvasReady (canvas) { this.data.myCanvas = canvas; }
  },
  created() {
     this.data.myCanvas = null;
  }
}
</script>

If you're not planning on using it inside the template though, you can just put it outside the component.

<template>
  <my-custom-canvas @ready="canvasReady">
</template>
<script>
const myCanvas = null;
export default {
  methods: {
    canvasReady (canvas) { myCanvas = canvas; }
  },
}
</script>

Upvotes: 1

Related Questions