DEV Community

Rafa Rafael
Rafa Rafael

Posted on

Implementing Infinite Scroll with Laravel and Vue.js 3

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);
});
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

src/App.vue

<template>
  <div id="app">
    <user-list></user-list>
  </div>
</template>

<script>
export default {
  name: 'App',
};
</script>
Enter fullscreen mode Exit fullscreen mode

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;
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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!

Top comments (2)

Collapse
 
lindamiles profile image
Linda

I really enjoyed your article—great insights! I'll be featuring it in tomorrow's issue of my daily tech newsletter, Daily Sandbox. Keep up the awesome work!

Collapse
 
rafaelogic profile image
Rafa Rafael

Thank you so much! I’m thrilled you enjoyed the article and really appreciate the feature in Daily Sandbox. It means a lot. I’ll definitely keep the content coming!