anggoran
anggoran8mo ago

Signals & Data Fetching

1. Should I declare useSignal on route or island? 2. How to fetch data? Make an async route? Do useEffect?
9 Replies
anggoran
anggoranOP8mo ago
I'm kinda confused about the solution, since we can't declare useSignal within async route.
marvinh.
marvinh.8mo ago
1. to declare a signal in an async route use:
const mySignal = signal(123)
const mySignal = signal(123)
The useSignal doesn't work because async routes are not components 2. Depends on where you want to fetch data. If on the server, fetch it in your route and pass it down. On the client, trigger fetch based on user interaction like on click or inside a useEffect
anggoran
anggoranOP8mo ago
in the tutorial it is stated that As a shortcut for combining a GET handler with a route, you can define your route as async. , so to fetch on server, async route and GET handler are the same?
marvinh.
marvinh.8mo ago
yep
anggoran
anggoranOP8mo ago
alright, thank you very much!
mrk
mrk8mo ago
Some thoughts: Would there be a reason to pass data wrapped in a signal from an async route to a client component/island? Reactivity is not carried over the wire and the server has no client/user interaction, so no need for reactivity there, right? I guess you where just answering for completeness @marvinh. , since signals are indeed serializable by fresh and sent over-the-wire. Just making sure I'm not missing out on some server signal use case 😃 This reminds me of a blogpost I read about Ryan Carniato where he hints on a future with server-to-client signals, that is, where reactivity trascends the server/client border. Maybe this could be done using WebSockets/SSE, definitively interesting...
marvinh.
marvinh.8mo ago
Yeah the reactivity transcending across the server client boundary is something I'd love to explore more this year. I feel like that's the direction frameworks are moving towards. Creating a signal in an async route may still make sense if it is passed to different islands. Both islands will subscribe to the exact same signal in the client in this case.
mrk
mrk8mo ago
Oh I see, so it does make sense as a great place to declare shared global signals for multiple islands to import 👌 ... And yeah, after using fresh for a while, the server-client boundary is what takes the most time to get used to and requires changing one's mental model (coming from SPA's myself at least). I see how this could hugely enhance DX if signal reactivity could cross this border. Apart from frameworks looking into these patterns, there's also SignalDB which accomplishes something similar (more like a Signals-based abstraction over arbitrary databases/datastores/apis), though it's framework agnostic. Might be of interest too 👍
Jarl André
Jarl André2mo ago
i have sort of a similar problem, with data fetching. I think my brain is hardwired for server side data fetching, and, since i know that route components like index.tsx and even _app.tsx is server side rendered, i find it difficult to understand that for ex in Home function in index.tx, that i cannot combine the use of useSignal AND fetch async data at the same time. If i convert the Home function to a function that takes request and context and make it async, the use of useSignal is no longer allowed and i cannot load data asynchronously .. i find it a bit wierd i have such problems grokking this because i have been working on and off backend and frontend for 15 years. Somehow Fresh seems to combine the two worlds in a rather peculiar way. So, lets say i want to load some data on the server side, for ex before i render the Counter island, in a "fresh" Fresh project, how do i go about changing the Home function in index.tsx? i propably only need a gentle kick in my leg to understand it, so be gentle 😄 probably need to move the contents of the Home function into another component? and convert Home to an async server side component ? haha .. sorry .. yes .. figured it out myself .. exactly as I described it routes/index.tsx:
import type { FreshContext } from "$fresh/server.ts";
import Example from "../components/Example.tsx";
import { test } from "../data/repo.ts";

export default async function Home(_req: Request, _ctx: FreshContext) {
const n = await test();
return <Example n={n} />
}
import type { FreshContext } from "$fresh/server.ts";
import Example from "../components/Example.tsx";
import { test } from "../data/repo.ts";

export default async function Home(_req: Request, _ctx: FreshContext) {
const n = await test();
return <Example n={n} />
}
components/Example.tsx:
import { useSignal } from "@preact/signals";
import Counter from "../islands/Counter.tsx";

export default function Example(props: { n: number }) {
const count = useSignal(props.n);

return (
<div class="px-4 py-8 mx-auto bg-[#86efac]">
<div class="max-w-screen-md mx-auto flex flex-col items-center justify-center">
<img
class="my-6"
src="/logo.svg"
width="128"
height="128"
alt="the Fresh logo: a sliced lemon dripping with juice"
/>
<h1 class="text-4xl font-bold">Welcome to Fresh</h1>
<p class="my-4">
Try updating this message in the
<code class="mx-2">./routes/index.tsx</code> file, and refresh.
</p>
<Counter count={count} />
</div>
</div>
);
}
import { useSignal } from "@preact/signals";
import Counter from "../islands/Counter.tsx";

export default function Example(props: { n: number }) {
const count = useSignal(props.n);

return (
<div class="px-4 py-8 mx-auto bg-[#86efac]">
<div class="max-w-screen-md mx-auto flex flex-col items-center justify-center">
<img
class="my-6"
src="/logo.svg"
width="128"
height="128"
alt="the Fresh logo: a sliced lemon dripping with juice"
/>
<h1 class="text-4xl font-bold">Welcome to Fresh</h1>
<p class="my-4">
Try updating this message in the
<code class="mx-2">./routes/index.tsx</code> file, and refresh.
</p>
<Counter count={count} />
</div>
</div>
);
}
✅ should be made more clear in fresh docs ... a simple example to show how to combine deno-postgres with island components hierarchy vups 🙈 https://fresh.deno.dev/docs/concepts/app-wrapper#-async-app-wrapper-2