ItalyPaleAle / svelte-spa-router

Router for SPAs using Svelte 3
MIT License
1.53k stars 105 forks source link

Load user data #305

Open notramo opened 1 year ago

notramo commented 1 year ago

Currently, the loading screen is displayed while the dynamically imported component is loading. However, it could be useful to load data from an API, and pass it to the component using props. Some components can be simpler in design if data is already available when they are instantiated. Also, it would be the same loading screen, so there was no glitch between the router loading screen and the component's loading screen.

ItalyPaleAle commented 1 year ago

Hi @notramo I am not sure I understand the issue. What loading screen?

jh12z commented 1 year ago

I'm also looking for the same functionality @notramo describes (correct me if I'm wrong). My component is expecting some data to be loaded and passed via props and that way I can avoid UI loading glitches easily.

It'd be nice if the options.props of the route accepts functions (async too) and waits until all the functions are resolved. Also it'd be nice for the function to receive the same detail as the events.

Something like:

<!-- App.svelte -->
<script>
  import Router from 'svelte-spa-router';
  import wrap from "svelte-spa-router/wrap.js";
  import Loading from './Loading.svelte';
  import Product from './Product.svelte';

  async function sleep(time) {
    return await new Promise(res => setTimeout(res, time));
  }

  function logEvent(event) {
    console.log(event.type, event.detail);
  }

  let routes = {
    "/product/:id": wrap({
      component: Product,
      loadingComponent: Loading,
      conditions: [
        async (detail) => {
          console.log("condition1", detail);
          await sleep(1000); // fake delay
          return true;
        }
      ],
      props: {
        product: async (detail) => {
          console.log("Loading product", detail);
          await sleep(1000); // fake delay
          return {
            name: `Product ${detail?.params?.id}`
          }
        }
      }
    })
  }
</script>
<Router {routes}
  on:conditionsFailed={logEvent}
  on:routeLoading={logEvent}
  on:routeLoaded={logEvent}
  />

<!-- Loading.svelte -->
<div>Loading ...</div>

<!-- Product.svelte -->
<script>
  export let product = {};
</script>
<div>Name: {product.name}</div>
jh12z commented 1 year ago

I implemented the functionality in 5 lines but then I found there is a discussion already in #283. I'll review the other PR.

notramo commented 1 year ago

Hi @notramo I am not sure I understand the issue. What loading screen?

The one that is currently shown while the asyncComponent is loading.

The solution proposed by @jh12z seems OK, but I'm not sure about how it handles changing route properties. E.g. if I visit /items/1 then change the URL to /items/2, does it reload the item from the API?