S
SolidJS•5mo ago
mihaaai

How to use `createResource` value to initialize another signal on the client?

I'm trying to fetch from my API a json that contains a link to Spotify preview (an audio) and then feed it to the audio primitive, the problem is that at render time it's undefined until it resolves the request and return the json, so the audio is undefined and I cannot play it.
const SpotifyPlayer = () => {
const [song] = createResource(fetchSong);
const [isPlaying, setIsPlaying] = createSignal<boolean>(false);
const [audio, controls] = createAudio(song().item.preview_url, isPlaying); // song() is possibly undefined, if I song()? TS stops complaining but the audio wn't play, because at the init of the component the song().item.preview_url is undefined

return <>...</>
}
const SpotifyPlayer = () => {
const [song] = createResource(fetchSong);
const [isPlaying, setIsPlaying] = createSignal<boolean>(false);
const [audio, controls] = createAudio(song().item.preview_url, isPlaying); // song() is possibly undefined, if I song()? TS stops complaining but the audio wn't play, because at the init of the component the song().item.preview_url is undefined

return <>...</>
}
How to handle such situations with Solid? Maybe with onMount? Typescript keeps complaining about the song() being possibly undefined and it's right, but how it's the correct way of using the values returned by createResources in the body of the function before it returns? For more context I'm using this within Astro in a client:only"solid-js" which means that the code is not wrapped in <Suspense> and it's executed only on the client (my API updates the last song played in Spotify each 10 mins so I need the component to also return the last song played at each refresh). If I set another client: directive it works without any problem but I'll only get the last song played during the last build of the app, insted of it being dynamic. No SSR is involved, everything is SSG
GitHub
solid-primitives/packages/audio at main · solidjs-community/solid-p...
A library of high-quality primitives that extend SolidJS reactivity. - solidjs-community/solid-primitives
2 Replies
Madaxen86
Madaxen86•5mo ago
You could create a child component which you mount (<Show when=...) when createResource has finished loading.
const SpotifyPlayer = () => {
const [song] = createResource<Audio>(fetchSong);
// song() is possibly undefined, if I song()? TS stops complaining but the audio wn't play, because at the init of the component the song().item.preview_url is undefined

return <Show when={song.state === "ready"} >
<Player song={song()!} />
</Show>
}

const Player = (props:{song:Audio}) => {
const [isPlaying, setIsPlaying] = createSignal<boolean>(false);
const [audio, controls] = createAudio(() => props.song.item.preview_url, isPlaying);
return <>...</>
}
const SpotifyPlayer = () => {
const [song] = createResource<Audio>(fetchSong);
// song() is possibly undefined, if I song()? TS stops complaining but the audio wn't play, because at the init of the component the song().item.preview_url is undefined

return <Show when={song.state === "ready"} >
<Player song={song()!} />
</Show>
}

const Player = (props:{song:Audio}) => {
const [isPlaying, setIsPlaying] = createSignal<boolean>(false);
const [audio, controls] = createAudio(() => props.song.item.preview_url, isPlaying);
return <>...</>
}
If you use solid-start (which can also be a SPA without SSR) you can use createAsync instead which is easier to handle and narrow if it is resolved.
mihaaai
mihaaaiOP•5mo ago
Thanks a lot for the suggestion, it worked flawlessly 😄
Want results from more Discord servers?
Add your server