javascriptvue.jsinfinitegrid

Infinitegrid duplicates API calls


I use vue-infinitegrid and I have realized in a browser that a backend API is called three times. Some code first (git):

<GridLayout
  ref="ig"
  :options="options"
  :layoutOptions="layoutOptions"
  @append="onAppend"
  @layout-complete="onLayoutComplete"
  @image-error="onImageError"
>
  <div slot="loading">Loading...</div>
  <div class="item" v-for="(item) in list" :key="item.key">
    <ViewItem :item="item"/>
  </div>
</GridLayout>

data() {
  return {
    start: 0,
    loading: false,
    list: [],
    isEnded: false,
    options: {
      isOverflowScroll: false,
      useFit: true,
      useRecycle: true,
      horizontal: false,
      align: 'center',
      transitionDuration: 0.2,
    },
    layoutOptions: {
      margin: 15,
      align: 'center',
    },
    pageSize: 3,
  };
},

methods: {
  async onAppend({ groupKey, startLoading }) {
    this.$log.debug(`onAppend group key = ${groupKey}`);
    const { list } = this;
    if (this.isEnded) return;
    const items = await this.loadItems();
    startLoading();
    this.list = list.concat(items);
  },
  async loadItems() {
    const start = this.start || 0, size = parseFloat(this.pageSize), { tag } = this;
    this.$log.debug(`loadItems start = ${start}, size = ${size}`);
    let res = await this.$store.dispatch('GET_ITEM_STREAM', { start, size, tag });
    if (res.length === 0) { // todo or smaller than requested
      this.$log.debug('loadItems no data');
      this.isEnded = true;
      this.$refs.ig.endLoading();
      return res;
    }
    if (this.exceptItem) {
      res = res.filter(item => item._id !== this.exceptItem._id);
    }
    this.start = start + res.length;
    this.$log.debug('loadItems finished');
    return res;
  },
  onLayoutComplete({ isLayout, endLoading }) {
    this.$log.debug(`onLayoutComplete isLayout = ${isLayout}`);
    if (!isLayout) {
      endLoading();
    }
  },

And some logs:

onAppend group key =
ItemList.vue:71 loadItems start = 0, size = 3
items.js:132 GET_ITEM_STREAM {"start":0,"size":3}
See more tips at https://vuejs.org/guide/deployment.html
ItemList.vue:83 loadItems finished
ItemList.vue:87 onLayoutComplete isLayout = false
ItemList.vue:62 onAppend group key =
ItemList.vue:71 loadItems start = 3, size = 3
items.js:132 GET_ITEM_STREAM {"start":3,"size":3}
ItemList.vue:62 onAppend group key =
ItemList.vue:71 loadItems start = 3, size = 3
items.js:132 GET_ITEM_STREAM {"start":3,"size":3}
2 ItemList.vue:83 loadItems finished
ItemList.vue:87 onLayoutComplete isLayout = false
ItemList.vue:62 onAppend group key =
ItemList.vue:71 loadItems start = 6, size = 3
items.js:132 GET_ITEM_STREAM {"start":6,"size":3}
ItemList.vue:62 onAppend group key =
ItemList.vue:71 loadItems start = 6, size = 3
items.js:132 GET_ITEM_STREAM {"start":6,"size":3}
2 ItemList.vue:83 loadItems finished
ItemList.vue:87 onLayoutComplete isLayout = false

I can see that start is incremented after onAppend is called. It looks like some concurrency issue, that the infinitegrid component does not wait until the REST call is finished and fires new event. Has anybody any experience with this component and knows how to handle this situation when I need to wait for a backend response?

Update

I have replaced async call with fixed data and it started to work correctly. So the trouble is with async.

// let items = await this.$store.dispatch('GET_ITEM_STREAM', { start, size, tag });
let items = [{ ...

Update:

Code sandbox with minimum reproducible scenerio: https://w56p2.csb.app/ The symptoms are different now, probably exhibiting the root cause - the event is emitted before the previous is processed.

https://github.com/naver/egjs-infinitegrid/issues/365


Solution

  • https://naver.github.io/egjs-infinitegrid/storybook/?path=/story/loading-bar-with-data-delay--grid-layout

    In startLoading and endLoading, the loading bar appears and disappears, and some functions are temporarily disabled (moveTo, useFit).

    The append and prepend work and must be prevented through the isProcessing method.

    onAppend({ groupKey, startLoading, currentTarget }) {
        if (currentTarget.isProcessing()) {
            return;
        }
    }
    

    Update

    https://naver.github.io/egjs-infinitegrid/storybook/?path=/story/examples-data-loading--wait-n-ready-template

    onRequestAppend(e) {
          const nextGroupKey = (+e.groupKey! || 0) + 1;
    
          e.wait(); // <--- Important!
          setTimeout(() => {
            e.ready(); // <--- Important!
            this.items = [...this.items, ...this.getItems(nextGroupKey, 10)];
          }, 1000);