33

I'm new to Vue. While making this component I got stuck here.

I'm making an AJAX request to an API that returns an array using this code:

import axios from 'axios';
export default {
  data() {
    return {
      tickets: [],
    };
  },
  methods: {
    getTickets() {
      axios.get(url)
        .then((response) => {
            console.log(response.data) //[{}, {}, {}]
            this.tickets = [...response.data]
            console.log(this.tickets) //proxy object
          })
    },
  },
  created() {
    this.getTickets();
  }
};

The problem is, this.tickets gets set to a Proxy object instead of the Array I'm getting from the API.

What am I doing wrong here?

user3840170
  • 26,597
  • 4
  • 30
  • 62
Eduardo Robles
  • 495
  • 1
  • 5
  • 7

5 Answers5

14

Items in data like your tickets are made into observable objects. This is to allow reactivity (automatically re-rendering the UI and other features). This is expected and the returned object should behave just like the array.

Check out the reactivity docs because you need to interact with arrays in a specific pattern or it will not update on the ui: https://v3.vuejs.org/guide/reactivity-fundamentals.html

If you do not want to have reactivity - maybe you never update tickets on the client and just want to display them - you can use Object.freeze() on response.data;

Katinka Hesselink
  • 3,961
  • 4
  • 20
  • 26
Joseph Connolly
  • 891
  • 11
  • 21
  • 2
    I just realized i can use it the same way i would use an array. It's just a little hard to debug using console.logs, that's for me anyways. Thanks for your reply! – Eduardo Robles Nov 19 '20 at 18:32
  • Glad to help, I will sometimes use console.log(JSON.parse(JSON.stringify(observableObject))) to make it easier to read. If you put it into your temlate it will render the output cleanly:
    {{tickets}}
    – Joseph Connolly Nov 19 '20 at 18:37
  • 3
    is this 100% true? I'm trying to check if an array .includes() a value and it keeps comparing to indices instead of the actual values. I have to check it against Object.values(array) instead. – Adam Starrh Jan 08 '21 at 17:44
  • 2
    OP asked about new Vue 3, and docs are for old 2.x version. If I remember correctly reactivity changed like a lot in new version and old docs are not true anymore – Kos Mar 07 '21 at 13:29
7

if you want reactive information use toRaw https://vuejs.org/api/reactivity-advanced.html#toraw

    const foo = {}
    const reactiveFoo = reactive(foo)
    
    console.log(toRaw(reactiveFoo) === foo) // true

or use unref if you donot want ref wrapper around your info

https://vuejs.org/api/reactivity-utilities.html#unref

Tarun_vella
  • 71
  • 2
  • 5
5

You can retrieve the Array response object from the returned Proxy by converting it to a JSON string and back into an Array like so:

console.log(JSON.parse(JSON.stringify(this.tickets)));
mike
  • 323
  • 3
  • 11
3

You're not doing anything wrong. You're just finding out some of the intricacies of using vue 3.

Mostly you can work with the proxied array-object just like you would with the original. However the docs do state:

The use of Proxy does introduce a new caveat to be aware of: the proxied object is not equal to the original object in terms of identity comparison (===).

Other operations that rely on strict equality comparisons can also be impacted, such as .includes() or .indexOf().

The advice in docs doesn't quite cover these cases yet. I found I could get .includes() to work when checking against Object.values(array). (thanks to @adamStarrh in the comments).

Katinka Hesselink
  • 3,961
  • 4
  • 20
  • 26
3
import { isProxy, toRaw } from 'vue';

let rawData = someData;

if (isProxy(someData)){
    rawData = toRaw(someData)
}