Tips for adding elements to a computed property in Vue

I've been working on implementing an infinite scroll feature in a Vue3 app. While everything is functioning well, I've hit a roadblock when it comes to loading more data once the user reaches the end of the page.

All profiles are initially stored in Vuex, but are rendered in batches as the user scrolls down the page.

My goal is to display an initial set of profiles, and then add more profiles to the array once the user reaches the bottom of the page.

To achieve this, I'm utilizing a computed property that waits for the Vuex array to load from the database. This ensures that the data is loaded before rendering. Additionally, the computed property recalculates each time new data is added.

Currently, the v-for directive is bound to this computed property. However, I am struggling to figure out how to push new profiles to this computed property. I attempted to assign the computed property to a component data property, but it seems that this approach is not effective.

Any assistance would be greatly appreciated.

<template>
  <div v-for="profile in loadedProfiles" :key="profile.id">
    {{ profile.name }}
  </div>
</template>

<script>
export default {

  data: () => ({
    loadedProfiles: this.computedLoadedProfiles()
  }),

   computed: {

    
    computedLoadedProfiles() {
      if (this.$store.state.numberOfProfilesLoaded === this.$store.state.numberOfProfilesLoadedInitially) {
        return this.$store.state.currentProfileList.slice(0, this.$store.state.numberOfProfilesLoadedInitially);
      }
    },

    methods: {
        loadMoreProfiles() {
            if($store.state.scrolledToBottom) {
                loadedProfiles.push(...) //push more profiles to loadedProfiles
            }
        }
    }
    
  },

}
</script>

<style>

</style>

Answer №1

Let's delve into how the store operates:

const { createApp, onMounted, computed } = Vue;
const { createStore } = Vuex;

const store = createStore({
  state: {
    profiles: [],
    visibleProfilesCount: 0,
    loading: false
  },
  actions: {
    // Need to implement actual server call
    loadMoreProfiles({ commit, state }) {
      commit('setLoading', true);
      return new Promise((resolve) => {
        setTimeout(() => {
          commit(
            "addProfiles",
            Array.from({ length: 30 }).map(
              (_, key) => key + state.profiles.length
            )
          );
          commit('setLoading', false);
          resolve();
        }, 1e3);
      });
    },
  },
  mutations: {
    addProfiles(state, profiles) {
      state.profiles.push(...profiles);
    },
    setLoading(state, loading) {
      state.loading = loading;
    },
    showMoreProfiles(state) {
      state.visibleProfilesCount += 10;
    },
  },
  getters: {
    visibleProfiles(state) {
      return state.profiles.slice(0, state.visibleProfilesCount);
    },
  },
});

const app = createApp({
  setup() {
    const showMore = () => {
      store.commit("showMoreProfiles");
      if (store.state.profiles.length < store.state.visibleProfilesCount) {
        store.dispatch("loadMoreProfiles");
      }
    };
    onMounted(showMore);
    return {
      visibleProfiles: computed(() => store.getters.visibleProfiles),
      loading: computed(() => store.state.loading),
      showMore,
    };
  },
});
app.use(store);
app.mount("#app");
.logger {
  position: fixed;
  width: 50vw;
  top: 0;
  bottom: 0;
  right: 0;  
}
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/vuex@4"></script>
<div id="app">
  <div v-for="profile in visibleProfiles" :key="profile">{{ profile }}</div>
  <div v-if="loading">Loading...</div>
  <button v-else @click="showMore">Load more</button>
  <pre class="logger" v-text="JSON.stringify({
    profiles: $store.state.profiles.length,
    visibleProfiles: $store.state.visibleProfilesCount,
    loading
  }, null, 2)"></pre>
</div>

To enhance this, connect showMore to scrolling instead of the button, and replace loadMoreProfiles action with a real server call to fetch more profiles and add them to the state.

One can choose not to store visibleProfilesCount and visibleProfiles in the store. They can be defined within your component as follows:

const visibleProfilesCount = ref(0)
const visibleProfiles = computed(
  () => store.state.profiles.slice(0, visibleProfilesCount.value)
)
const showMore = () => {
  visibleProfilesCount.value += 10;
  if (store.state.profiles.length < visibleProfilesCount.value) {
    store.dispatch("loadMoreProfiles");
  }
};

The core concept is: visibleProfiles is a computed property, or getter in the store, (meaning derived state), resulting from two other state properties: profiles and visibleProfilesCount. Any change in these state properties will impact the computed value.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What are some strategies for increasing efficiency in my drag and drop process?

Update #2 Wow, transition was stuck at .35s. My CSS just wasn't updating properly :( UPDATE: Anyone know if requestAnimationFrame could help with this? I've got a rotating image reel and I want users to be able to swipe left or right to switch ...

What is the best way to read a local text file and store its contents in a string variable within a

Within my ReactNative project, I am seeking to retrieve the content of static text files and store it in a string variable. Here is an example of how I would like to achieve this: var content = loadPlainTextFile("resources/tags.txt"); var tags = content.s ...

Application becomes unresponsive following database write caused by an infinite loop

I have a user_dict object that is generated by fetching data from a Firebase database. Once the user_dict object is created, I store a copy of it within a profile child under the uid. Although the necessary information is successfully saved to the databas ...

Distinctive titles for JavaScript constructors/prototypes compared to classes

When working with JavaScript ES6, classes allow us to write code like this: class RectangularShape { constructor(height, width) { this.height = height; this.width = width; } getArea() { return this.height * this.width } static some ...

Escaping quotes in JavaScripts is an important skill to

I have a table called posts. When I add a title enclosed in quotes ("This the new") to the posts table and then try to delete the post using an onclick javascript function, I encounter the following issue: echo "<td><a class='btn btn-danger& ...

Initializing an HTML5 video player directly from an Array

I am trying to populate a video player on my webpage with an array of videos. Here is the code I have so far: var current = 0; var videos = ["01", "02", "03", "04"]; function shuffle(array) { var currentIndex = array.length, temporaryValue, randomInde ...

What is the best way to trim a string property of an object within an array?

I am seeking a solution to access the "description" property of objects within an array and utilize a string cutting method, such as slice, in order to return an array of modified objects. I have attempted using for loops but have been unsuccessful. Here ...

How does the call method on array.prototype.includes work with arguments x and y?

Curious about the functionality of array.prototype.includes.call(x, y);. Discovered that includes() confirms if an array has the specified value and provides a true or false result. Learned that call() invokes this alongside any optional arguments. The ...

I am unable to make changes to the Text Field component in Material-UI

After developing a React App using Material-UI, I decided to create independent Components. Below are the independent components (<PanelDiv/>): render() { return ( <div className="panelDiv-component" style={{display:this.prop ...

Validate form for radio group

Hello Experts, I am currently working on developing a form that includes a JavaScript validation function for a radio group. The main objective is to have a division pop up when either "Monday" or "Tuesday" is checked, and no popup when "None" is selected ...

Using the OR condition in the ternary operator within ReactJS

Recently, I have started working on a ReactJS project focusing on menus. In this project, I have successfully implemented logic for the active menu feature. For instance, when a user is on page 2, the corresponding menu item will be highlighted as active. ...

Notifying with Socket.IO in Node.js

Hey there, I'm currently working on implementing a notification system but have hit a roadblock. I've sent an invitation to a user to join the club. socket.on("notify", async (message) => { // invite the user John Doe io.to('socke ...

Guide on extracting a parameter from a response URL using Angular (Stripe Connect)

To initiate the setup process for Stripe Connect's standalone account, the first crucial step is obtaining the user's permission in order to establish the connection. This initial interaction can be facilitated by directing the user to the follo ...

Error Encountered: AJAX Request Failed with 400 Bad Request

I've been using mithril.js to communicate with my node back-end. I followed the documentation and added an AJAX request, but there seems to be limited information available on mithril. Encountered Error: mithril.js:2130 POST http://localhost:3000/a ...

Issue with Tabulator: The top and bottom calculations do not shift position when a column is toggled. Seeking a solution to toggle a column and refresh the table without losing the current

My main objective is to toggle the visibility of toggles while maintaining consistent formatting. However, I currently face an issue where using a filter achieves this but results in losing the current scroll position of the tabulator, which is not accepta ...

How can we automate the process of assigning the hash(#) in Angular?

Is it possible to automatically assign a unique hash(#) to elements inside an ngFor loop? <div *ngFor="let item of itemsArray; index as i"> <h3 #[item][i]> {{ item }} </h3> </div> I would like the outp ...

Updating the Scale of the Cursor Circle on my Portfolio Site

I attempted to find tutorials on creating a unique circle cursor that can hide the regular mouse cursor as well. After implementing it with a difference blend mode, I encountered an issue where I wanted the scale to change when hovering over a link. The ...

Leveraging vuetifyjs v-file-input component for uploading images

Having some trouble with the v-file-input component when trying to upload an image to an s3 bucket. Whenever I attempt to retrieve the photo, it appears as an empty object. <v-file-input v-model='test' type='file' ></v- ...

The JQuery chosen dropdown experiences a visual issue when placed inside a scrollbar, appearing to be "cut

Good day, I've been using the jQuery "chosen" plugin for a dropdown menu, but I encountered an issue with it being located in a scrollable area. The problem is that the dropdown items are getting cut off by the outer div element. I have provided a si ...

Tips for managing vue event using javascript code

I am looking to utilize JavaScript code to develop a custom Vue component. Although I can successfully create the component and add it to the DOM using JS, I am uncertain about how to handle events with JavaScript. import listitem from './listitem&ap ...