0

I have some pagination on an Api route which was used to fetch the post's data.

When the pagination is on page 2, I would like to add the fetched data from the page and add to the existing array.

Function used to fetch the data

const posts = ref([]);
const page = ref(1);

const getPosts = async (page) => {
        await axios
            .get("/api/explore/gallery/?page=" + page)
            .then((response) => {
                if (page === 1) {
                    posts.value = response.data;
                } else {
                    posts.value = { ...posts.value, ...response.data };
                }
            });
    };

So when the page is 2 onward, the fetched data will add to the existing array.

The result if I used posts.value = { ...posts.value, ...response.data };

The id start from 51 instead of 1 - 100.

The id start from 51 instead of 1 - 100.

I have also tried posts.value = [ ...posts.value, ...response.data ]; but returned

PostApi.js:12 Uncaught (in promise) TypeError: Invalid attempt to spread non-iterable instance.
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.
    at _nonIterableSpread (PostApi.js:12:39)
    at _toConsumableArray (PostApi.js:10:131)
    at eval (PostApi.js?c0c4:15:21)

response.data look like this

enter image description here

post.value look like this

enter image description here

James Wong
  • 155
  • 2
  • 14
  • 1
    An array uses `[ ... ]` not `{ ... }` Also, you need to make sure you're spreading the actual array, not something else. Why are you referring to `posts.value` is `posts` is an array? There's maybe a `posts[0].value` but an array does not have a `.value` –  Apr 20 '22 at 09:21
  • 1
    You can use the [concat method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) to add value to the existing array : `posts.value = posts.value.concat(response.data)` – RenaudC5 Apr 20 '22 at 09:28
  • @ChrisG, i referred to this solution from other people https://stackoverflow.com/a/71110698/17737657 – James Wong Apr 20 '22 at 10:08
  • 1
    In other words, the loaded array is `response.data.data` and the existing array is `post.value.data`, which means you need `post.value.data = [ ...post.value.data, reponse.data.data ]` –  Apr 20 '22 at 10:10
  • @ChrisG, there is a value because i am using `Vue`'s `ref` – James Wong Apr 20 '22 at 10:19
  • @RenaudC5, `concat` does not seem to be working. `Uncaught (in promise) TypeError: posts.value.concat is not a function at eval (PostApi.js?c0c4:15:47` – James Wong Apr 20 '22 at 10:31
  • 1
    @Chai Fuu Wong It seems like `ref` can't take an array as it's a mutable ref object, which has a single property value that points to the inner value. Try instantiate the array with `const post = {value: []}` or `const post = []` – RenaudC5 Apr 20 '22 at 11:42

2 Answers2

1

You could do this with a cache to provide more control over how much data accumulates on the client. This answer provides a reasonable looking LRU cache. Combining it with your api might look like this...

const cache = new LRU(8);

const getPosts = async (page) => {
    const result = cache.get(page);
    if (result) return Promise.resolve.result;
    return await axios
        .get("/api/explore/gallery/?page=" + page)
        .then((response) => {
            cache.set(page, response.data);
            return response.data;
        });
};

Your markup would show the current value of posts. Whatever user event that triggers your paging would do this...

// in an async method
this.posts = await getPosts(pageComputedFromUI);

This would have about the same effect as your solution (which caches everything and never expels anything), but with the benefit of memory kept under your control -- and at the cost of more network requests.

danh
  • 62,181
  • 10
  • 95
  • 136
0

I have found the solution,

const getPosts = async (page) => {
    await axios
        .get("/api/explore/gallery/?page=" + page)
        .then((response) => {
            if (page === 1) {
                posts.value = response.data;
            } else {
                posts.value = {
                    ...posts.value,
                    data: [...posts.value.data, ...response.data.data],
                };
            }
        });
};
James Wong
  • 155
  • 2
  • 14
  • Glad it works, but consider this: often, the reason an api pages is because there's too much data for the client to handle all at once. A client that navigates to too many pages might end up with too much data. The simpler alternative is to just fetch on every page change, and cache at most one or two pages in each direction. – danh Apr 20 '22 at 22:51
  • @danh, Thx for your suggestion, but maybe you can explain in more detail cuz I am not quick to understand. – James Wong Apr 20 '22 at 23:30
  • @danh, what would be the best approach to handle things like infinite scroll to display the posts? currently, i am using pagination(laravel) in the backend and fetching them in the front end, and storing them in an array, as you can see above ? but like you said the client would end up getting much and much more data . – James Wong Apr 20 '22 at 23:41