0

So i'm trying to lazy load articles with infinite scrolling, with inertia-vue and axios, backend is laravel 6.0. Since I don't want to do unnecessary request i'm giving over the total amount of articles to the component. I'm also tracking the amount of already loaded articles in the component data.

props: {
    article_count: Number,
   },
data: function () {
    return {
        loaded: 0,
        scrolledToBottom: false,
        articles: [],
    }
},

The articles that are loaded are all being put into articles, and scrolledToBottom keeps track if the user has scrolled to the bottom. I have already checked if this refers to the vue component and has the data properties, which it does.

methods: {
    load: function (nextToLoad) {
        for (let i = nextToLoad; i < nextToLoad + 10; i++){
            if (this.loaded <= this.article_count){
                this.$axios.get(route('api_single_article', i))
                    .then(response => {
                        if (response.status == 200 && response.data != null) {
                            console.log(this.loaded);
                            this.articles.push(response.data);
                        }
                        this.loaded++;
                    })
                    .catch(error => {
                        if (error.response.status != 404) {
                            console.log(error);
                            console.log(this.loaded);
                            this.loaded++;
                        }
                    });
            }
        }
        console.log(this.loaded);
    },
    scroll: function () {
        window.onscroll = () => {
            let bottomOfWindow = document.documentElement.scrollTop + window.innerHeight === document.documentElement.offsetHeight;

            if (bottomOfWindow) {
                this.load(this.loaded + 1);
            }
        }
    }
}

The weird part is, that if i log this.loaded in the response / error arrow function it always returns 0. If i do it outside the response it also returns 0, but if i log this the loaded property has the supposed value after the loop has ran through, despite it being logged every time the loop is run. I have already showed this to a friend and he also couldn't fix it. The behaviour just seems weird to me and i don't know how else i should do, since i'm very inexperienced with vue.

Thanks for the help.

  • why is `this.$axios`, it should be just `axios` and is this `route('api_single_article', i)` laravel stuff!! – Md. Amirozzaman Jan 10 '20 at 12:07
  • since axios by default somehow didn't work so i added it with ```Vue.prototype.$axios = axios;``` and with https://github.com/tightenco/ziggy you can pass your laravel routes to js – David Docampo Jan 10 '20 at 13:24
  • for test purpose that axios is make `request` and get a `response`,try with hard coded route url e.g: `'api/article/'+i` – Md. Amirozzaman Jan 10 '20 at 13:28
  • I already tested that, Delena Malan's tip has lead me to the solution, thanks for the help – David Docampo Jan 10 '20 at 13:39

1 Answers1

0

Might be a concurrency thing. Remember that the axios call is asynchronous so the loop will continue before the responses have been received.

So it could be the many responses are received at the same time and that loaded is then still 0 at that point. Looks like this won't be the case. Apparently JavaScript will process callbacks one after the other.

I'm not sure how JavaScript handles concurrent increments though so I can't exactly explain how that plays into effect here.

From your implementation, it looks like you'd want to turn the load function into an asynchronous function (using the async) keyword and then use the await before the axios call to ensure that you have received a response before making another request.

For interest's sake, maybe have a look at your network tab and count how many requests are being made. I suspect there will be more requests made than this.article_count.

D Malan
  • 10,272
  • 3
  • 25
  • 50
  • Yeah there are 10 requests being made at the same time. After I added the async await and fixed a logic error ```if (this.loaded < this.article_count``` instead of ```if (this.loaded <= this.article_count``` it works properly now. Thanks a lot :) – David Docampo Jan 10 '20 at 13:38