How to use server function & suspense

I will be frank, I have some experience with React but this is my first dive into Solid coming from Astro I'm trying to have a fallback loading component, that is replaced by data fetched from the server when available I figured the best way to do this was an asynchronous server function, I am not claiming there is a bug I think I just did something wrong Here is my high-level code since I can't really share more:
async function getUserInfo() {
"use server";
// Mimics server speed, network latency, etc.
await new Promise((resolve) => setTimeout(resolve, 300));

// TO-DO: real data / connections here
return {
avatar: "~/assets/img/placeholders/generic-avatar.jpg",
name: "User Name",
};
}

//... component defined
const [fetchedInfo] = createResource(getUserInfo);

return (
<Suspense fallback={<UserInfoFallback />}>
<img
class="aspect-square size-full"
src={fetchedInfo()?.avatar}
decoding="sync"
loading="eager"
alt="User Avatar"
draggable="false"
/>
<span class="text-neutral-content flex w-full flex-col gap-0.5 truncate text-left">
<p class="block truncate text-sm font-semibold">
{fetchedInfo()?.name}
</p>
<p class="block truncate text-[0.7rem] font-light">
{fetchedInfo()?.email}
</p>
</span>
</Suspense> )
async function getUserInfo() {
"use server";
// Mimics server speed, network latency, etc.
await new Promise((resolve) => setTimeout(resolve, 300));

// TO-DO: real data / connections here
return {
avatar: "~/assets/img/placeholders/generic-avatar.jpg",
name: "User Name",
};
}

//... component defined
const [fetchedInfo] = createResource(getUserInfo);

return (
<Suspense fallback={<UserInfoFallback />}>
<img
class="aspect-square size-full"
src={fetchedInfo()?.avatar}
decoding="sync"
loading="eager"
alt="User Avatar"
draggable="false"
/>
<span class="text-neutral-content flex w-full flex-col gap-0.5 truncate text-left">
<p class="block truncate text-sm font-semibold">
{fetchedInfo()?.name}
</p>
<p class="block truncate text-[0.7rem] font-light">
{fetchedInfo()?.email}
</p>
</span>
</Suspense> )
7 Replies
ⱼ ₒ ₑ
ⱼ ₒ ₑOP4d ago
In the future there will likely be API calls and it will be implemented differently but I'm just trying to grasp basic ideas ATM
Brendonovich
Brendonovich4d ago
What's the problem you're having? The only wrong thing i can see is passing the ~/assets/img string directly into src
ⱼ ₒ ₑ
ⱼ ₒ ₑOP3d ago
This doesn't work? It just gives a "Script error" and no discernable output for me to work with
peerreynders
peerreynders3d ago
Just to be clear you are using SolidStart (which is required for "use server" RPC)? Usually people throw the SolidStart tag onto the topic.
ⱼ ₒ ₑ
ⱼ ₒ ₑOP3d ago
Yes Sorry I should have done that
peerreynders
peerreynders3d ago
- Created fresh SolidStart(TS) "basic" template - Dropped the following into src/routes/about.tsx - Just works.
// file: src/routes/about.tsx
import { Suspense, Show } from 'solid-js';
import { createAsync } from '@solidjs/router';
import { Title } from '@solidjs/meta';

async function getUserInfo() {
'use server';
await new Promise((resolve) => setTimeout(resolve, 300));

console.log('getUserInfo', new Date().toString());
return {
avatar: 'https://placehold.co/100x100/93c5fd/ffffff?text=Generic Avatar',
name: 'User Name',
};
}

export default function About() {
const fetchedInfo = createAsync(getUserInfo);

return (
<main>
<Title>About</Title>
<h1>About</h1>
<Suspense fallback={'loading'}>
<Show when={fetchedInfo()}>
{(user) => (
<>
<img
src={user().avatar}
decoding="sync"
loading="eager"
alt="User Avatar"
draggable="false"
/>
<span>
<p>{user().name}</p>
<p>{user().email}</p>
</span>
</>
)}
</Show>
</Suspense>
</main>
);
}
// file: src/routes/about.tsx
import { Suspense, Show } from 'solid-js';
import { createAsync } from '@solidjs/router';
import { Title } from '@solidjs/meta';

async function getUserInfo() {
'use server';
await new Promise((resolve) => setTimeout(resolve, 300));

console.log('getUserInfo', new Date().toString());
return {
avatar: 'https://placehold.co/100x100/93c5fd/ffffff?text=Generic Avatar',
name: 'User Name',
};
}

export default function About() {
const fetchedInfo = createAsync(getUserInfo);

return (
<main>
<Title>About</Title>
<h1>About</h1>
<Suspense fallback={'loading'}>
<Show when={fetchedInfo()}>
{(user) => (
<>
<img
src={user().avatar}
decoding="sync"
loading="eager"
alt="User Avatar"
draggable="false"
/>
<span>
<p>{user().name}</p>
<p>{user().email}</p>
</span>
</>
)}
</Show>
</Suspense>
</main>
);
}
ⱼ ₒ ₑ
ⱼ ₒ ₑOP3d ago
TY

Did you find this page helpful?