Footer

Hi everyone. I'm trying to create my footer using a context that I have for SEO and retrive my social networks from Sanity CMS, but I'm facing the error on the image The component code is on the thread. Can anyone help me?
No description
34 Replies
Daniel Sousa @TutoDS
On app.tsx:
<Router
preload={true}
root={(props) => (
<SeoContextProvider>
<MetaProvider>
<DefaultSeo />

<AosInit />
<Header />

<Suspense fallback={<LoadingRocket />}>{props.children}</Suspense>

<Footer />
</MetaProvider>
</SeoContextProvider>
)}
>
<Router
preload={true}
root={(props) => (
<SeoContextProvider>
<MetaProvider>
<DefaultSeo />

<AosInit />
<Header />

<Suspense fallback={<LoadingRocket />}>{props.children}</Suspense>

<Footer />
</MetaProvider>
</SeoContextProvider>
)}
>
Daniel Sousa @TutoDS
import { createAsync } from '@solidjs/router';
import {
type Accessor,
type JSXElement,
createContext,
createMemo,
useContext,
} from 'solid-js';
import { getSeoSettings } from '~/cms';
import type { Settings } from '~/shared/types';

type SeoContextProps = NonNullable<Pick<Settings, 'title' | 'keywords'>> &
Partial<Pick<Settings, 'slogan' | 'defaultDescription'>>;

const SeoContext = createContext<Accessor<SeoContextProps>>();

const SeoContextProvider = (props: { children: JSXElement }) => {
const seoSettings = createAsync(() => getSeoSettings());

const value = createMemo(
() =>
({
title: seoSettings()?.title ?? 'Impulsionar',
defaultDescription: seoSettings()?.defaultDescription,
slogan: seoSettings()?.slogan,
keywords: seoSettings()?.keywords ?? [
'impulsionar',
'marketing',
'design',
'social media',
'branding',
],
}) satisfies SeoContextProps,
);

return <SeoContext.Provider value={value}>{props.children}</SeoContext.Provider>;
};

function useSeo() {
const context = useContext(SeoContext);

if (!context) {
throw new Error('useSeo mut be used within a `SeoContextProvider`.');
}

return context();
}

export { SeoContext, SeoContextProvider, useSeo };
import { createAsync } from '@solidjs/router';
import {
type Accessor,
type JSXElement,
createContext,
createMemo,
useContext,
} from 'solid-js';
import { getSeoSettings } from '~/cms';
import type { Settings } from '~/shared/types';

type SeoContextProps = NonNullable<Pick<Settings, 'title' | 'keywords'>> &
Partial<Pick<Settings, 'slogan' | 'defaultDescription'>>;

const SeoContext = createContext<Accessor<SeoContextProps>>();

const SeoContextProvider = (props: { children: JSXElement }) => {
const seoSettings = createAsync(() => getSeoSettings());

const value = createMemo(
() =>
({
title: seoSettings()?.title ?? 'Impulsionar',
defaultDescription: seoSettings()?.defaultDescription,
slogan: seoSettings()?.slogan,
keywords: seoSettings()?.keywords ?? [
'impulsionar',
'marketing',
'design',
'social media',
'branding',
],
}) satisfies SeoContextProps,
);

return <SeoContext.Provider value={value}>{props.children}</SeoContext.Provider>;
};

function useSeo() {
const context = useContext(SeoContext);

if (!context) {
throw new Error('useSeo mut be used within a `SeoContextProvider`.');
}

return context();
}

export { SeoContext, SeoContextProvider, useSeo };
This is my SEO context
Raqueebuddin Aziz
which index.tsx is the error referring?
Daniel Sousa @TutoDS
Is the footer/index.tsx
Raqueebuddin Aziz
does commenting the show block fix it? just to narrow down the issue if yes try commenting just the For block after that to try and narrow it down more
Daniel Sousa @TutoDS
If I remove the Show apparently works For example If I put console.log(value.slogan), the console shows me undefined and on the browser shows me the correct value I'm doing something wrong? thats why I put the Show on that part
Raqueebuddin Aziz
I think we are talking about different shows are you talking about seo.slogan show? I was talking about socialNetworks one
Daniel Sousa @TutoDS
Yeah, sorry for the social networks I remove it, but, for works, I need to remove the show on the seo.slogan but If remove that, the footer works but the slogan isn't displayed
Daniel Sousa @TutoDS
Keep having this
No description
Daniel Sousa @TutoDS
and if I click on the index.tsx
Raqueebuddin Aziz
so if I understand correctly if the slogan show is removed the error goes away?
Daniel Sousa @TutoDS
goes to that part
No description
Daniel Sousa @TutoDS
Yes, but the slogan isn't displayed :/ Basically I did this:
{/*<Show when={seo.slogan} keyed>*/}
{/*{(slogan) => (*/}
<p class="text-center text-sm text-zinc-400 md:text-left">{seo.slogan}</p>
{/*)}*/}
{/*</Show>*/}
{/*<Show when={seo.slogan} keyed>*/}
{/*{(slogan) => (*/}
<p class="text-center text-sm text-zinc-400 md:text-left">{seo.slogan}</p>
{/*)}*/}
{/*</Show>*/}
and works, but not slogan :/
Raqueebuddin Aziz
try removing keyed, seems like you don't need a keyed show
Daniel Sousa @TutoDS
Without the keyed
No description
Raqueebuddin Aziz
try adding this createEffect(() => console.log(seo)) to see what are the value diff bw server and client
Daniel Sousa @TutoDS
On the browser ⤴️
No description
Daniel Sousa @TutoDS
On console ⤴️
No description
Raqueebuddin Aziz
what about the object itself
Daniel Sousa @TutoDS
function useSeo() {
const context = useContext(SeoContext);

if (!context) {
throw new Error('useSeo mut be used within a `SeoContextProvider`.');
}

return context();
}
function useSeo() {
const context = useContext(SeoContext);

if (!context) {
throw new Error('useSeo mut be used within a `SeoContextProvider`.');
}

return context();
}
⬆️ on the useSeo should I return the Accessor instead of the value? Let me see
Raqueebuddin Aziz
cannot say without seeing the useSeo implementation oh it's there nvm
Daniel Sousa @TutoDS
{
"title": "Impulsionar",
"slogan": "Perseguimos tudo o que o Digital nos permite alcançar.",
"defaultDescription": null,
"keywords": [
"marketing",
"design",
"desenvolvimento web",
"social media"
]
}
{
"title": "Impulsionar",
"slogan": "Perseguimos tudo o que o Digital nos permite alcançar.",
"defaultDescription": null,
"keywords": [
"marketing",
"design",
"desenvolvimento web",
"social media"
]
}
⬆️ From the createEffect
{}
{}
⬆️ Without createEffect on console
Raqueebuddin Aziz
yes I think you should return context and not context()
Daniel Sousa @TutoDS
const getSeoSettings = cache(async (): Promise<SeoSettings | undefined> => {
'use server';

try {
const seo = await client.fetch<SeoSettings>(getSeoSettingsQuery);

return {
...seo,
title: seo.title ?? 'Impulsionar',
keywords: seo.keywords ?? [
'impulsionar',
'marketing',
'design',
'social media',
'branding',
],
};
} catch {
return;
}
}, 'seo-settings');
const getSeoSettings = cache(async (): Promise<SeoSettings | undefined> => {
'use server';

try {
const seo = await client.fetch<SeoSettings>(getSeoSettingsQuery);

return {
...seo,
title: seo.title ?? 'Impulsionar',
keywords: seo.keywords ?? [
'impulsionar',
'marketing',
'design',
'social media',
'branding',
],
};
} catch {
return;
}
}, 'seo-settings');
This is my fetching data to sanity cms I think solves
Raqueebuddin Aziz
solved? try returning an empty object in the catch, maybe that helps
Daniel Sousa @TutoDS
No 😦 I try again and already back, if remove the show on the slogan works but don't show the slogan, if add it again, i have the same error I'm out of ideas to be honest 😦 Apparently, if I remove the createMemo on the contexts seems works but let me try to restart the server again to check But without the createMemo seems that I have a refresh on the ui Thank you for your time and sorry for be a noob, but I'm totally lost at this point 🥲 Could be because of the createMemo? :/ The only way that fix it is fetching the data again on the footer instead of using the context, so for now I will follow with that approach
Brendonovich
Brendonovich4mo ago
try putting a Suspense around your whole root or even around the whole router, consuming seoSettings inside the createMemo is causing SeoContextProvider to suspend outside of the Suspense you already have using a plain function rather than memo should also work since that moves the evaluation of setSettings from the memo to the place that invokes the function
Daniel Sousa @TutoDS
So instead of have the Suspense for the children, wrap my entire root content in Suspense Thanks I will try that 🙏 Again, sorry for the noob mistakes/questions
Brendonovich
Brendonovich4mo ago
yeah that should work though it's fine to have multiple suspenses, one for the whole root and one for the routes also i'd recommend to not call context() inside useSeo as it will no longer be reactive unless you're calling useSeo directly inside JSX or an effect
Daniel Sousa @TutoDS
Ok one question for examplo I'm fetching the blog posts, shouldn't use a suspense for the list of posts because already have a global suspense?
Brendonovich
Brendonovich4mo ago
That depends on how you want the list of posts to behave during navigations If during navigation to the list you want to block navigation until the list is done, then just rely on the global suspense If you want the navigation to occur straight away and show a fallback while the posts load, then add a dedicated Suspense You can add and omit Suspense in different parts of your app to control how things should load
Daniel Sousa @TutoDS
but If I put the second suspense, the global will be ignored?
Brendonovich
Brendonovich4mo ago
The global one will still handle SeoContextProvider suspending, it just won't handle everything below the second Suspense (assuming you haven't changed SeoContextProvider to not suspend anymore) Otherwise yeah it won't really do anything
Daniel Sousa @TutoDS
Thanks @Brendonovich Seems that works, I'm already using the context on the footer and change the useSeo to return the acessor instead of the value
Want results from more Discord servers?
Add your server