[Vuejs]-How to push elements to computed property in Vue?

0👍

Here’s the store mechanics:

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

const store = createStore({
  state: {
    profiles: [],
    visibleProfilesCount: 0,
    loading: false
  },
  actions: {
    // replace with actual call to server
    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>

All that’s left is to link showMore to the scroll action, instead of the button, and replace loadMoreProfiles action with an actual call to server to get the more profiles and add them to state.

Obviously, you don’t have to keep visibleProfilesCount and visibleProfiles in the store. They can be declared in your component, along these lines:

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 gist of it is: visibleProfiles is computed, or getter on store, (which means derived state), resulting from two other state properties: profiles and visibleProfilesCount. Whenever one of the state props changes, the computed changes.

Leave a comment