Server Side Fetching

Hi I want to fetch data from server side and render the title based on it's content like in PHP. I want to execute the fetch request to api from server side because I want to render the page to client when fetch is ready. Do someone could provide an example script?
export default function MyFetch() {
// data fetching
return <Title>{data.title}</Title>
}

export default function MyFetch() {
// data fetching
return <Title>{data.title}</Title>
}

30 Replies
Brendonovich
Brendonovich3w ago
If you use createResource and deferStream thats what will happen
Jason.json
Jason.jsonOP2w ago
Ok but where do I have to write it? Ok never mind now I can see that Just read the docs Thank you I got what I needed I made example route to see how it will execute
import { Title } from "@solidjs/meta";
import { useNavigate, useSearchParams } from "@solidjs/router";
import { useAPIFetch } from "~/lib/utils";

export default function Index() {
const [params] = useSearchParams();
const navigate = useNavigate();

if (!params.id) {
navigate("/404");
return;
}

const [texturepack] = useAPIFetch(`texturepacks?id=${params.id}`, {
deferStream: true,
});

return (
<Title>{texturepack()[0].title}</Title>
);
}
import { Title } from "@solidjs/meta";
import { useNavigate, useSearchParams } from "@solidjs/router";
import { useAPIFetch } from "~/lib/utils";

export default function Index() {
const [params] = useSearchParams();
const navigate = useNavigate();

if (!params.id) {
navigate("/404");
return;
}

const [texturepack] = useAPIFetch(`texturepacks?id=${params.id}`, {
deferStream: true,
});

return (
<Title>{texturepack()[0].title}</Title>
);
}
It still shows me that texturepack()[0] is undefined, but when I open the api page with the same id I get json as expected.
[
{
"title": "Sukuna [32x]",
"author": "Hiiro",
"version": "1.16^",
"description": "TexturPack dostosowany do PvP. Pozytywnie wpływa na twoją wydajność.",
"download": "https://lisia-nora.pl/texturpaki/Sukuna [32x]/Sukuna [32x].zip",
"thumbnail": "https://lisia-nora.pl/texturpaki/Sukuna [32x]/thumbnail.webp",
"icon": "https://lisia-nora.pl/texturpaki/Sukuna [32x]/icon.webp"
}
]
[
{
"title": "Sukuna [32x]",
"author": "Hiiro",
"version": "1.16^",
"description": "TexturPack dostosowany do PvP. Pozytywnie wpływa na twoją wydajność.",
"download": "https://lisia-nora.pl/texturpaki/Sukuna [32x]/Sukuna [32x].zip",
"thumbnail": "https://lisia-nora.pl/texturpaki/Sukuna [32x]/thumbnail.webp",
"icon": "https://lisia-nora.pl/texturpaki/Sukuna [32x]/icon.webp"
}
]
I expect it to be ready after fetching it to use it
Brendonovich
Brendonovich2w ago
The data from createResource will be undefined initially, deferStream doesn't stop that, but it will stop the HTML response from being sent until the data has been fetched and the <Title> updates if the html being sent in the response is correct then it's functioning as intended
Jason.json
Jason.jsonOP2w ago
yeah but it trows error cuz the first element is undefined
Brendonovich
Brendonovich2w ago
Use optional chaining: texturepack()[0]?.title
Jason.json
Jason.jsonOP2w ago
ok but would it work on link preview like so in like meta tags? I want to include it to my project But they have to be rendered before the response i think so
Brendonovich
Brendonovich2w ago
yeah as long as deferStream is there the response will be delayed
Jason.json
Jason.jsonOP2w ago
Oh ok thanks! I will tell you if it works when I finish that part Do you know maybe why i get this getter error? Cannot set property image_url of #<Object> which has only a getter Route code
return (
<Show when={texturepack()}>
<Title>{texturepack()[0].title}</Title>
<MetaPageProvider
description={texturepack()[0].description}
image_url={texturepack()[0].thumbnail}
title={`Zobacz texturepack ${texturepack()[0].title}! 🦊`}
url={`https://lisia-nora.pl/textures?id=${params.id}`}
/>
</Show>
);
return (
<Show when={texturepack()}>
<Title>{texturepack()[0].title}</Title>
<MetaPageProvider
description={texturepack()[0].description}
image_url={texturepack()[0].thumbnail}
title={`Zobacz texturepack ${texturepack()[0].title}! 🦊`}
url={`https://lisia-nora.pl/textures?id=${params.id}`}
/>
</Show>
);
MetaPageProvider code
import { MetaProvider, Meta, Link } from "@solidjs/meta";

interface MetaPageProviderProps {
description: string;
image_url: string;
title: string;
url: string;
}

export default function MetaPageProvider(props: MetaPageProviderProps) {
props.image_url = `https://lisia-nora.pl/${props.image_url}`;

return (
<MetaProvider>
<Meta property="og:description" content={props.description} />
<Meta property="og:locale" content="pl_PL" />
<Meta property="og:url" content={props.url} />
<Meta property="og:title" content={props.title} />
<Link rel="image_src" href={props.image_url} />
<Meta property="og:type" content="webapp" />
<Meta property="og:image" content={props.image_url} />
</MetaProvider>
);
}
import { MetaProvider, Meta, Link } from "@solidjs/meta";

interface MetaPageProviderProps {
description: string;
image_url: string;
title: string;
url: string;
}

export default function MetaPageProvider(props: MetaPageProviderProps) {
props.image_url = `https://lisia-nora.pl/${props.image_url}`;

return (
<MetaProvider>
<Meta property="og:description" content={props.description} />
<Meta property="og:locale" content="pl_PL" />
<Meta property="og:url" content={props.url} />
<Meta property="og:title" content={props.title} />
<Link rel="image_src" href={props.image_url} />
<Meta property="og:type" content="webapp" />
<Meta property="og:image" content={props.image_url} />
</MetaProvider>
);
}
Brendonovich
Brendonovich2w ago
because you're writing to props.image_url like i said before, define a separate function
export default function MetaPageProvider(props: MetaPageProviderProps) {
const full_image_url = () => `https://lisia-nora.pl/${props.image_url}`;

return (
<MetaProvider>
<Meta property="og:description" content={props.description} />
<Meta property="og:locale" content="pl_PL" />
<Meta property="og:url" content={props.url} />
<Meta property="og:title" content={props.title} />
<Link rel="image_src" href={full_image_url()} />
<Meta property="og:type" content="webapp" />
<Meta property="og:image" content={props.image_url} />
</MetaProvider>
);
}
export default function MetaPageProvider(props: MetaPageProviderProps) {
const full_image_url = () => `https://lisia-nora.pl/${props.image_url}`;

return (
<MetaProvider>
<Meta property="og:description" content={props.description} />
<Meta property="og:locale" content="pl_PL" />
<Meta property="og:url" content={props.url} />
<Meta property="og:title" content={props.title} />
<Link rel="image_src" href={full_image_url()} />
<Meta property="og:type" content="webapp" />
<Meta property="og:image" content={props.image_url} />
</MetaProvider>
);
}
Jason.json
Jason.jsonOP2w ago
Oh now I see it
Brendonovich
Brendonovich2w ago
a) writing to props is bad, and b) components only run once so if you read props or signals in the component body it won't be reactive
Jason.json
Jason.jsonOP2w ago
sure I just wanted to do not create another variable to handle the image_url
Brendonovich
Brendonovich2w ago
you could inline the string into the href={}
Jason.json
Jason.jsonOP2w ago
oh yeah sure I thaught this way it would be cleaner how can i navigate to 404 when api result is an empty array?
export default function Index() {
const [params] = useSearchParams();
const navigate = useNavigate();

if (!params.id) {
navigate("/404");
return;
}

createEffect(() => {
if (texturepack().lenght === 0) {
navigate("/404");
}
});

const [texturepack] = useAPIFetch<TexturePackData[]>(
`texturepacks?id=${params.id}`,
{
deferStream: true,
}
);

return (
<Show when={texturepack()}>
<Title>{texturepack()[0].title}</Title>
<MetaPageProvider
description={texturepack()[0].description}
image_url={texturepack()[0].thumbnail}
title={`Zobacz texturepack ${texturepack()[0].title}! 🦊`}
url={`https://lisia-nora.pl/textures?id=${params.id}`}
/>
<DynamicIcon icon_url={texturepack()[0].icon} />
</Show>
);
}
export default function Index() {
const [params] = useSearchParams();
const navigate = useNavigate();

if (!params.id) {
navigate("/404");
return;
}

createEffect(() => {
if (texturepack().lenght === 0) {
navigate("/404");
}
});

const [texturepack] = useAPIFetch<TexturePackData[]>(
`texturepacks?id=${params.id}`,
{
deferStream: true,
}
);

return (
<Show when={texturepack()}>
<Title>{texturepack()[0].title}</Title>
<MetaPageProvider
description={texturepack()[0].description}
image_url={texturepack()[0].thumbnail}
title={`Zobacz texturepack ${texturepack()[0].title}! 🦊`}
url={`https://lisia-nora.pl/textures?id=${params.id}`}
/>
<DynamicIcon icon_url={texturepack()[0].icon} />
</Show>
);
}
Brendonovich
Brendonovich2w ago
that should work, i think you misspelled length tho
Jason.json
Jason.jsonOP2w ago
oh ok ok
Jason.json
Jason.jsonOP2w ago
No description
Jason.json
Jason.jsonOP2w ago
nah
Brendonovich
Brendonovich2w ago
you're only checking that texturepack() is undefined in the <Show>, you should check for [0] too when={texturepack()?.[0]}
Jason.json
Jason.jsonOP2w ago
ok like so: texturepack()?.[0]?.description ok thanks it works :ryan: https://lisia-nora.pl/testroute?id=24746dd2-b3fe-11ef-a5c9-3cecef0f5064 It does not show the meta content :(( Like image etc
Jason.json
Jason.jsonOP2w ago
this how it looked like with using static json file
No description
Jason.json
Jason.jsonOP2w ago
on messanger
Brendonovich
Brendonovich2w ago
how is deferStream getting passed to createResource?
Jason.json
Jason.jsonOP2w ago
I maybe found the error
export function useAPIFetch<T>(
url: string,
resourceOptions?: ResourceOptions<T>,
requestOptions?: RequestInit
) {
const baseUrl = production() ? prodServer : devServer;
const fullUrl = `${baseUrl}/api/${url}`;

const fetchMethod = async () => {
try {
const response = await fetch(fullUrl, requestOptions);

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

const data = await response.json();
return data;
} catch (error) {
console.error("Fetch error:", error);
throw error;
}
};

return resourceOptions
? createResource(fetchMethod, resourceOptions)
: createResource(fetchMethod);
}
export function useAPIFetch<T>(
url: string,
resourceOptions?: ResourceOptions<T>,
requestOptions?: RequestInit
) {
const baseUrl = production() ? prodServer : devServer;
const fullUrl = `${baseUrl}/api/${url}`;

const fetchMethod = async () => {
try {
const response = await fetch(fullUrl, requestOptions);

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

const data = await response.json();
return data;
} catch (error) {
console.error("Fetch error:", error);
throw error;
}
};

return resourceOptions
? createResource(fetchMethod, resourceOptions)
: createResource(fetchMethod);
}
I put requestOptions ? [...] instead of resourceOptions ? [...]
Brendonovich
Brendonovich2w ago
ahh yep
Jason.json
Jason.jsonOP2w ago
a small mistake haha
Brendonovich
Brendonovich2w ago
i think you should be fine to just do createResource(fetchMethod, resourceOptions)?
Jason.json
Jason.jsonOP2w ago
oh yeah good point I tried that before and it throw error at me cuz i probably used the other param as always
Jason.json
Jason.jsonOP2w ago
Zobacz texturepack Sukuna [32x]! 🦊
TexturPack dostosowany do PvP. Pozytywnie wpływa na twoją wydajność.
Jason.json
Jason.jsonOP2w ago
Oh yeah now it works It's in Polish btw Thanks man for helping me figure it out
Want results from more Discord servers?
Add your server