Infinite scroll is a more modern alternative to traditional pagination, providing a seamless user experience. In this blog post, we’ll implement infinite scroll in a Vue.js 3 application using Laravel as the backend.
Prerequisites
- Basic knowledge of Laravel and Vue.js 3.
- A Laravel project with an API to paginate data (e.g., User model).
Section 1: Setting Up the Basic Vue.js 3 Component for Infinite Scroll
Step 1: Create the Backend API
Create a simple API in your Laravel application to return paginated data:
routes/api.php
use App\Models\User;
use Illuminate\Http\Request;
Route::get('/users', function (Request $request) {
return User::paginate(10);
});
Step 2: Create the UserList Component with Infinite Scroll
Modify the UserList component to implement infinite scroll:
src/components/UserList.vue
<template>
<div>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr v-for="user in users" :key="user.id">
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
</tr>
</tbody>
</table>
<div v-if="loading" class="loading">
Loading more users...
</div>
</div>
</template>
<script>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import axios from 'axios';
export default {
setup() {
const users = ref([]);
const loading = ref(false);
let page = ref(1);
let observer;
const fetchUsers = async () => {
loading.value = true;
try {
const response = await axios.get(`/api/users?page=${page.value}`);
if (response.data.data.length > 0) {
users.value.push(...response.data.data);
page.value++;
}
} catch (error) {
console.error(error);
} finally {
loading.value = false;
}
};
const handleScroll = () => {
const scrollableHeight = document.documentElement.scrollHeight - window.innerHeight;
const scrolledFromTop = window.scrollY;
if (scrollableHeight - scrolledFromTop < 100 && !loading.value) {
fetchUsers();
}
};
onMounted(() => {
fetchUsers();
window.addEventListener('scroll', handleScroll);
});
onBeforeUnmount(() => {
window.removeEventListener('scroll', handleScroll);
});
return {
users,
loading,
};
},
};
</script>
<style>
.loading {
text-align: center;
margin-top: 10px;
}
</style>
Step 3: Integrate the Component in Your Vue App
Include the component in your Vue app:
src/main.js
import { createApp } from 'vue';
import App from './App.vue';
import UserList from './components/UserList.vue';
const app = createApp(App);
app.component('user-list', UserList);
app.mount('#app');
src/App.vue
<template>
<div id="app">
<user-list></user-list>
</div>
</template>
<script>
export default {
name: 'App',
};
</script>
Section 2: Managing Infinite Scroll with Vuex
If you need to manage the state of infinite scroll across different components, Vuex can help.
Step 1: Set Up Vuex Store
Create a store to manage the users and infinite scroll state:
src/store/index.js
import { createStore } from 'vuex';
import axios from 'axios';
export default createStore({
state: {
users: [],
loading: false,
page: 1,
},
mutations: {
ADD_USERS(state, users) {
state.users.push(...users);
},
SET_LOADING(state, loading) {
state.loading = loading;
},
INCREMENT_PAGE(state) {
state.page++;
},
},
actions: {
async fetchUsers({ commit, state }) {
if (state.loading) return;
commit('SET_LOADING', true);
try {
const response = await axios.get(`/api/users?page=${state.page}`);
if (response.data.data.length > 0) {
commit('ADD_USERS', response.data.data);
commit('INCREMENT_PAGE');
}
} catch (error) {
console.error(error);
} finally {
commit('SET_LOADING', false);
}
},
},
getters: {
users(state) {
return state.users;
},
loading(state) {
return state.loading;
},
},
});
Step 2: Update the UserList Component
Modify the UserList component to use Vuex for managing the infinite scroll state:
src/components/UserList.vue
<template>
<div>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr v-for="user in users" :key="user.id">
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
</tr>
</tbody>
</table>
<div v-if="loading" class="loading">
Loading more users...
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
import { onMounted, onBeforeUnmount } from 'vue';
export default {
computed: {
...mapGetters(['users', 'loading']),
},
methods: {
...mapActions(['fetchUsers']),
handleScroll() {
const scrollableHeight = document.documentElement.scrollHeight - window.innerHeight;
const scrolledFromTop = window.scrollY;
if (scrollableHeight - scrolledFromTop < 100 && !this.loading) {
this.fetchUsers();
}
},
},
created() {
this.fetchUsers();
},
mounted() {
window.addEventListener('scroll', this.handleScroll);
},
beforeUnmount() {
window.removeEventListener('scroll', this.handleScroll);
},
};
</script>
<style>
.loading {
text-align: center;
margin-top: 10px;
}
</style>
Step 3: Integrate Vuex into Your Vue App
Ensure that Vuex is integrated into your Vue.js application:
src/main.js
import { createApp } from 'vue';
import App from './App.vue';
import store from './store'; // Import the Vuex store
import UserList from './components/UserList.vue';
const app = createApp(App);
app.use(store); // Use Vuex store in the app
app.component('user-list', UserList);
app.mount('#app');
Step 4: Modify App.vue
Your main App.vue
should include the UserList component:
<!-- src/App.vue -->
<template>
<div id="app">
<user-list></user-list>
</div>
</template>
<script>
export default {
name: 'App',
};
</script>
By following these steps, you’ve successfully implemented infinite scroll in a Vue.js 3 application, using Laravel as the backend. Whether you’re handling state locally within a component or globally with Vuex, infinite scroll provides a smooth, modern user experience. The Vuex integration is particularly useful when managing the scroll state across multiple components or views, ensuring that your application remains scalable and maintainable.
This approach not only enhances user experience by loading data dynamically as the user scrolls but also optimizes performance by loading only necessary data at a time.
Enjoy!