PirateApp
PirateApp

Reputation: 6240

Shallow Routing throws 404 when typing address directly or reloading item url. How to fix this?

Shallow Routing works well when clicking on an item Shallow routing works well when clicking on an item

Shallow routing throws 404 when typing item url directly in browser Shallow routing throws 404 when typing item url directly

Link to Stackblitz that shows the issue

src/routes/(news)/+layout.svelte

<script lang="ts">
import './../../app.css'
import { page } from '$app/stores';
import { pushState } from '$app/navigation';
import { MediaQuery } from 'svelte/reactivity';
const { children, data } = $props();

const large = new MediaQuery('min-width: 800px');
    const hasNoDetailSelected = $derived.by(() => {
        return (
            typeof $page.state.id === 'undefined' && typeof $page.state.title === 'undefined'
        );
    });

  function onClickItem() {
    pushState('/news/abcdabcd-abcd-abcd-abcd-abcdabcdabcd/title-1', {id: 'abcdabcd-abcd-abcd-abcd-abcdabcdabcd', title: 'title-1'})
  }

</script>

    <header class="header">
        <h1>
            <a data-sveltekit-preload-data="off" href="/">TestNewsApp</a>
        </h1>
    </header>

{#if large.current}
<main style="flex-direction: row">
  <div class="news-list-container">
    <nav>
    <ul>
      <li onclick={onClickItem}>Item 1</li>
    </ul>
    </nav>
  </div>
  <div class="news-detail-container">
    {@render children()}
  </div>
</main>
{:else if !large.current && hasNoDetailSelected}
<main style="flex-direction: column">
  <div class="news-list-container">
    <nav>
    <ul>
      <li onclick={onClickItem}>Item 1</li>
    </ul>
    </nav>
  </div>
</main>
{:else}
<main style="flex-direction: column">
<div class="news-detail-container">
  {@render children()}
</div>
</main>

{/if}

<style>
.news-detail-container {
  background-color: lightyellow;
  flex: 1;
}
.news-list-container {
  background-color: lightcyan;
  flex: 1;
}
main {
  display: flex;
  flex: 1;
}
</style>

src/routes/(news)/+page.svelte

<script lang='ts'>
import {page} from '$app/stores';
</script>

{#if $page.state.id && $page.state.title}
<p>Detail Page</p>
{:else}
<p>Popular News</p>
{/if}

Question

Upvotes: -1

Views: 19

Answers (1)

PirateApp
PirateApp

Reputation: 6240

  • I think I fixed it but I am not sure if this is the right way
  • Basically you need to handle both shallow and deep routing for SSR cases
  • I created a /news/[id]/[title]/+page.svelte route to handle the params when SSR triggers this route

routes/(news)/news/[id]/[title]/+page.svelte

<script lang='ts'>
  import {page} from '$app/state'
  const {data, id, title} = $props()
</script>

<p>Detail Page What? {id || page.params.id} {title || page.params.title}</p>

  • Now you need to reuse this svelte file as a component for handling shallow routing

routes/(news)/+page.svelte

<script lang='ts'>
import {page} from '$app/stores';
import DetailPage from './news/[id]/[title]/+page.svelte'
</script>

{#if $page.state.id && $page.state.title}
<DetailPage id={$page.state.id} title={$page.state.title} />
{:else}
<p>Popular News</p>
{/if}

  • Notice how the DetailPage component is being used
  • The condition from routes/(news)/+layout.svelte has to be modified as well to handle SSR and params
    const hasNoDetailSelected = $derived.by(() => {
        return (
            typeof $pageFromStore.state.id === 'undefined' && typeof $pageFromStore.state.title === 'undefined' && typeof pageFromState.params.id === 'undefined' && typeof pageFromState.params.title === 'undefined'
        );
    });

Here is the fixed REPO from stackblitz

  • If this is not the way to do things, feel free to suggest

Upvotes: 0

Related Questions