skip to Main Content

I’m trying to accomplish the following but I don’t even know if it is even possible with Vue as I’m struggling to get the desired result:

I have an endpoint for an API which returns many objects within an array.

I am successfully rendering the data within my Vue application but I wanted to know if it is possible for Vue to “track” when the array has been updated with more objects and then render those in the view.

I am using setInterval to perform a GET request every 10 minutes and the new data is going into the object within my data() correctly but the changes are not reflected within the view.

At the moment I am changing a boolean from true to false at the beginning and end respectively so that the view is rendered again with v-if.

My goal is to create a simple Twitter feed app that performs a GET request every 10 minutes, collects the tweets, puts them into my Vue instance and show them in the view without having to reload the page/re-render the component. Like an automatic Twitter feed that just constantly loads new tweets every 10 minutes.

Is this even possible? I’ve tried using the Vue.set() method but that hasn’t made any difference.

If it’s not possible, what would be the best way to implement something similar?

Here is my code:

JavaScript:

new Vue({
  el: '#app',
  data: {
    items: [],
  },
  created() {
    this.load();
    setInterval(() => this.load(), 5000);
  },
  methods: {
    load() {
      axios.get('https://reqres.in/api/users?page=2')
      .then(response => {
        this.items = response.data.data;
      });
    }
  }
});

HTML

<div id="app">
  <p v-for="item in items">
    {{ item.first_name }}
  </p>
</div>

CodePen: https://codepen.io/tomhartley97/pen/VwZpZNG

In the above code, if the array is updated by the GET request, the chances are not reflected within the view?

2

Answers


  1. Yes it is possible. The way you need to set new reactive properties in your Vue instance is the following:

    For Object properties: Vue.set(this.baseObject, key, value)
    The baseObject cannot be a Vue instance or the base data() object, so you will have to declare a container property.

    For Array entries use native array methods: e.g. Array.prototype.push().
    Using Vue.set(array, arrayIndex, newArrayElement) does not work

    Hence, your solution might look something line that:

    <script>
    export default {
      data() {
        return {
          response: [],
        };
      },
    
      mounted() {
        setInterval = (() => this.getData), 600000);
      }
    
      methods: {
        async getData() {
          const res = await request();
          const resLength = res.data.length;
          for (let i = 0; i < resLength; i++) {
            // check if entry is already in array
            const entryExists = this.response.some((entry) => {
              return entry.id === res.data[i].id
            })
            if (!entryExists) {
              // this will make the array entries responsive, but not nested Objects
              this.response.push(res.data[i]);
              // to create nested responsive Objects you will have to set them explicitly
              // e.g. Vue.set(this.response[this.response.indexOf(res.data[i])], nestedObjectKey, res.data[i].nestedObject)
            }
          }
        }
      }
    };
    </script>
    
    Login or Signup to reply.
  2. Well, I view the codepen, I known why your view do not get update: the api response always return the same array!

    Try to return different data.


    The api returns an array, so the data defines

    data() {
      return {
        array: [] // array that api returns
      }
    }
    

    The template may look like this

    <div v-for="item in array">
    </div>
    

    And the update methods

    update() {
      setInterval(async () => {
        let resp = await api()
    
        this.array = resp.data.concat(this.array)
    
      }, TEN_MINUTES)
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search