solid-jsdynamic-urlsolid-start

Solid-Start seems to not always read URL parameter correctly


I want to use a slug in the URL (localhost:3000/birthdays/:id) to get an ID and then fetch that item using Pocketbase's JS SDK.

On the first attempt, I get this error in my browser:

Cannot read properties of undefined (reading 'id')

Sometimes, refreshing the page actually does render the page as expected:

I expected that every time this would read the item's ID from the URL and then use it to fetch the rest of the data about that item.

import { createSignal, createResource, Show } from "solid-js";
import { pb } from "~/services/pb.js";
import { useRouteData } from "solid-start";
import { useParams } from "@solidjs/router";
import toast, { Toaster } from "solid-toast";

export function routeData() {
  const params = useParams();
  const [birthday, { mutate, refetch }] = createResource(async () => {
    const record = await pb.collection("birthdays").getOne(params.id, {});
    console.log(record);
    return record;
  });
  return { birthday, refetch };
}

export default function Page() {
  const { birthday, refetch } = useRouteData();
  const [debugMode, setDebugMode] = createSignal(false);

  return (
    <main>
      <div>{birthday().id}</div>
    </main>
  );
}

Solution

  • You are returning a resource from the routeData function, meaning it is not readily available.

    A resource starts in pending state and the value remains undefined until it resolves to a value.

    https://www.solidjs.com/docs/latest#createresource

    You should make sure data is available when you access it, using either conditional rendering or a Suspense component.

    Here is how to do it using conditional rendering:

    const App = () => {
      const { birthday, refetch } = useRouteData();
    
      return (
        <Switch>
          <Match when={birthday.state === 'pending'}>Pending</Match>
          <Match when={birthday.state === 'errored'}>Error</Match>
          <Match when={birthday.state === 'ready'}>
            <div>{birthday().id}</div>
          </Match>
        </Switch>
      );
    }