#How to trigger server function for SSR when transitioning routes?

1 messages · Page 1 of 1 (latest)

true pendant
#

Is there any way to achieve a new SSR call to the backend for each route I navigate() with useNavigate() within a [slug] pattern?

I have a createAsync() in [slug].tsx that is supposed to get some data from the backend based on the route I get to, but it triggers only with a full refresh of the tab in the browser or fisrt page load, if I try to navigate() from inside the app the createAsync() function is not called anymore, it's a "use server" declared function, with a cache() wrapper, just like the examples on docs.

Ideally I wouldn't use <A> components and stick to useNavigate() but I'm open to anything would make this work.

Maybe this is the correct behavior of my setup but I couldn't find anything related to my use-case in the docs

potent monolith
true pendant
#

Sure:
/path/to/[slug].tsx This is the page itself

import { cache, useParams } from "@solidjs/router";
import { getApiEndpoint } from "~/lib/websocket";

export const getInitialProps = cache(async () => {
  "use server";
  const params = useParams();
  // make call to backend with params.slug
  const res = await apiService.fetch(url);
  const info = await res.json();

  if (res.status === 200) return info;
  return {};
}, "slug");

// Adding this or not doesn't make difference
export const route = {
  load: () => getInitialProps(),
};

const Slug = () => {
  const info = createAsync(async () => await getInitialProps());
  return <div>{info().user}</div>
}

export default Slug
#

NavigatorItem.tsx This is one of the navigation components that is mounted right inside the <Router> but not inside the [slug].tsx page

import { useNavigate } from "@solidjs/router";

const NavigatorItem = () => {
  const navigate = useNavigate();
  return <div onClick={() => navigate("/path/to/another-slug", { replace: true })}>...</div>
}

app.tsx The Root:

import { Router } from "@solidjs/router";
import { FileRoutes } from "@solidjs/start/router";
import { MetaProvider, Title } from "@solidjs/meta";
import { Suspense } from "solid-js";

import NavigatorItem from "~/components/Header/NavigatorItem";
import "./app.css";

const App = () => {
  return (
    <Router
      root={(props) => (
        <MetaProvider>
          <Title>App</Title>

          <NavigatorItem />
          <Suspense>{props.children}</Suspense>
        </MetaProvider>
      )}
    >
      <FileRoutes />
    </Router>
  );
};

export default App;

The problem is that getInitialProps() gets triggered only on full refresh or first load, if I click on <NavigatorItem /> the route changes but the content isn't fetched for the new slug

potent monolith
#

You shouldn't use useParams in a server function. Those hooks are meant to be used inside components.
You may pass the the slug instead as a param to the server function like this:


const getInitialProps = cache(async (slug: string) => {
  'use server';
  return fetch(url + slug) //or whatever
}, 'get-nums');

export const route = {
  preload: ({ params }) => getInitialProps(params.slug), //preload provides a callback with params,...
} satisfies RouteDefinition;

export default function Home() {
  const params = useParams();
  const info = createAsync(() => getInitialProps(params.slug));
  //...
return "..."
}
#

And instead of using a div with onClick you may prefer to use an anchor tag a or A so hovering them will trigger the preload function to fetch the new data before the user click. This way you have almost immediate page transitions as the data is probably already there when the user clicks.