In this tutorial, you’ll learn how to build an infinite scroll without using any 3-rd party packages. Ready?
Let’s break our goal down:
1. We need to detect if the user has scrolled to the bottom of the page. I’ve already covered this case in another article.
2. Load/fetch more items if the user has reached the bottom of the page.
Nothing complicated, I wouldn’t recommend installing a custom npm package.
Vue.js infinite scroll full example
new Vue({
el: "#app",
data: {
scrolledToBottom: true, // make sure it's set to true
isLoadingMore: null,
moreItems: []
},
methods: {
scroll () {
window.onscroll = () => {
let bottomOfWindow = Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop) + window.innerHeight === document.documentElement.offsetHeight
if (bottomOfWindow) {
if (this.itemsPagination.next && this.scrolledToBottom) {
this.scrolledToBottom = false
this.isLoadingMore = true
this.$store.dispatch('LOAD_ITEMS_PAGINATION', { pagination: this.itemsPagination.next }).then((response) => {
setTimeout(() => {
if (this.$store.getters.getItemsPagination.results) {
this.moreItems.push(...this.$store.getters.getItemsPagination.results)
}
this.isLoadingMore = false
this.scrolledToBottom = true
}, 300)
}, error => {
console.log(error)
this.isLoadingMore = false
})
}
}
}
}
},
mounted () {
this.scroll()
},
computed: {
...mapGetters({
items: 'getItems',
itemsPagination: 'getItemsPagination'
})
},
created () {
this.$store.dispatch('LOAD_ITEMS') // replace it with your action
}
})
This example works like this when the component is loaded we immediately dispatch a Vuex action LOAD_ITEMS
(you should replace it with your own action).
We then access a list of items using a computed property items and render it in the HTML template, however you like.
If you’re using a back-end server for your API calls, e.g. Django REST Framework make sure Pagination setting is on. As we’ll be using it to fetch more items.
Call a scroll()
method in the mounted()
function:
mounted () {
this.scroll()
}
Now every time the user reaches the bottom of the page the scroll()
method will load more items if they exist (by dispatching a LOAD_ITEMS_PAGINATION
action and pushing the results to the moreItems
array).
It won’t dispatch LOAD_ITEMS_PAGINATION
action if there are no items to load.
HTML part
In the HTML part of your component, you can first render a list of items using v-for
loop and then below it check using v-if
if there are items in the moreItems
array and render them again using the v-for
loop.
Store.js (NEW!)
// getters.js
const getters = {
getItems (state) {
return state.items
},
getItemsPagination: (state) => {
return state.itemsPagination
}
}
// actions.js
LOAD_ITEMS ({ commit }) {
return new Promise((resolve, reject) => {
axios.get(process.env.VUE_APP_BASE_URL + 'api/items/')
.then(response => {
resolve(response)
commit('SET_LOADED_ITEMS', response.data.results)
commit('SET_LOADED_ITEMS_PAGINATION', response.data)
})
.catch(error => {
reject(error)
console.log(error)
})
})
},
LOAD_ITEMS_PAGINATION ({ commit }, { pagination }) {
return new Promise((resolve, reject) => {
axios.get(pagination)
.then(response => {
resolve(response)
commit('SET_LOADED_ITEMS_PAGINATION', response.data)
})
.catch(error => {
reject(error)
console.log(error)
})
})
}
// index.js -> mutations part
SET_LOADED_ITEMS (state, payload) {
state.items = payload
},
SET_LOADED_ITEMS_PAGINATION (state, payload) {
state.itemsPagination = payload
},
Easy peasy.
If you find this post useful, or if you have any questions, please let me know in the comments below.
Cheers,
Renat Galyamov
Want to share this with your friends?
👉renatello.com/vue-js-infinite-scroll
PS: Make sure you check other Vue.js tutorials, e.g. how to create global components in Vue.js.
Good info, but incomplete for people following along. Need to include your store.js at the very least or link to the full working code.
Thanks Darius. I thought it would be enough as everyone has their own way of implementing store.js. I might add a full example later
Hi , nice example and nice work ,but incomplete, we need to see what is in your state, and how you handle pagination.
cheers
Hi Hanucka, it will depend on your backend (API server). In the example above I was using Django REST Framework.