Search code examples
javascriptsveltesapper

Fetch new page when user clicks a button using Svelte and Sapper


I am stuck at the part that fetch more data when user clicks a button on bottom of a page using Svelte and Sapper.

Here is the code.

 <script context="module">
  export function preload(page) {
    return this.fetch(`https://reqres.in/api/users?page=${$count}`) // I know this is not goint to work. but when the button is clicked, I want to fetch page 2 and merge it with page 1 data, show data in ascending order(page1, page2)
    .then(res1 => {
      return res1.json()
    }).then(res2 => {
      return { 
        currentPage: res2.page,
        per_page: res2.per_page,
        notices: res2.data,
        total: res2.total,
        totalPage: res2.total_pages
      }
    })
  }
</script>

<script>
  import { count } from '../../store.js'; // export const count = writable(1); from store.js file
  export let currentPage; // 1
  export let per_page; // 6
  export let notices; 
  export let total; // 12
  export let totalPage; // 2

  const handleClick= () => {
    if ($count < totalPage) {
      count.update(n => n + 1); // update count 1 to 2 and want to deliver changed value to fetch new page
    }
  }
</script>

<main>
  <div id="container">
    <h1 class="cont-tit">Notice Board</h1>

    <div class="noti-list-wrap">
    {#each notices as notice, i}
      <ul class="noti-list">
        <li>
          <a rel=prefetch href={`notice/${notice.id}`}>
            <p class="tit">{`${notice.first_name} ${notice.last_name}`}</p>
            <hr />
            <p class="date">
              {`notice no.${i}`}
            </p>
          </a>
        </li>
      </ul>
    {/each}
      <div class="show-more" on:click={handleClick}>show me more</div>
    </div>
  </div>
</main>

At first I thought I could use $count to fetch page 2 data but import count store inside script context="module" won't work.

Is there a way to deliver changed value of store to function preload?


Solution

  • Don't try to load the extra data inside preload. Instead, treat that as the initial data — which it is — and append to it the normal way.

    This is a simplified version — it doesn't worry about error handling, race conditions, or an initial page other than 1 — to give a general idea of what I mean:

    <script context="module">
      export async function preload(page) {
        const res = await this.fetch('https://reqres.in/api/users?page=1');
        const data = await res.json();
    
        return { 
          currentPage: data.page,
          per_page: data.per_page,
          notices: data.data,
          total: data.total,
          totalPage: data.total_pages
        };
      }
    </script>
    
    <script>
      export let currentPage;
      export let per_page;
      export let notices;
      export let total;
      export let totalPage;
    
      const load_more = async () => {
        currentPage += 1;
        const res = await fetch('https://reqres.in/api/users?page=' + currentPage);
        const data = await res.json();
    
        notices = notices.concat(data.data);
      };
    </script>
    
    <!-- other stuff -->
    {#if currentPage < totalPage}
      <button on:click={load_more}>show me more</button>
    {/if}