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

I have a categories array, which is loaded once (in created hook) and then it is static all the time. I render this array values in a component template.

<template>
    <ul>
        <li v-for="item in myArray">{{ item }}</li>
    </ul>
</template>

My data property looks (it does not include myArray - I dont want reactive binding):

data() {
    return {
        someReactiveData: [1, 2, 3]
    };
}

My create hook:

created() {
    // ...
    this.myArray = ["value 1", "value 2"];
    // ...
}

Problem is, that Vue throw error - I cant use myArray in a template, because this variable is not created when the DOM is created - mounted.

So how to do this? Or where can be stored component constants?


Solution 1:

Vue sets all the properties in the data option to setters/getters to make them reactive. See Reactivity in depth

Since you want myArray to be static you can create it as a custom option which can be accessed using vm.$options

export default{
    data() {
        return{
            someReactiveData: [1, 2, 3]
        }
    },
    //custom option name myArray
    myArray: null,
    created() {
        //access the custom option using $options
        this.$options.myArray = ["value 1", "value 2"];
    }
}

you can iterate over this custom options in your template as follows:

<template>
    <ul>
        <li v-for="item in $options.myArray">{{ item }}</li>
    </ul>
</template>

Here is the fiddle

Solution 2:

Actually, setting properties on this in created() should work out of the box:

<template>
  <div id="app">
    <ul>
      <li v-for="item in myArray" :key="item">
        {{ item }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "app",
  created() {
    this.myArray = [
      'item 1',
      'item 2'
    ];
  }
};
</script>

will render

<div id="app">
  <ul>
    <li>
      item 1
    </li>
    <li>
      item 2
    </li>
  </ul>
</div>

Demo here: https://codesandbox.io/s/r0yqj2orpn .

Solution 3:

I prefer using static data (non reactive) like this:

Create a mixin (i name it static_data.js) with the follow content

import Vue from 'vue'

Vue.prototype.$static = {}

export default {
  beforeCreate () {
    const vue_static = this.$options.static
    const vue_static_destination = this.$static || this

    if (vue_static && typeof(vue_static) === 'function') {
      Object.assign(vue_static_destination, vue_static.apply(this))
    } else if (vue_static && typeof(vue_static) === 'object') {
      Object.assign(vue_static_destination, vue_static)
    }      
  }
}

In your components where you want to use static data you can do:

import use_static_data from '@mixins/static_data'

export default {
  mixins: [use_static_data],

  static: () => ({
    static_value: 'Vue is awesome'
  }),

  created () {
    console.log(this.$static.static_value); // Vue is awesome
  }
}

There is also a package vue-static

Credits here.