I'm trying to get createEffect to update my userDetails signal with the data retrieved from createResource. However, when the page launches, the createEffect only runs the first initial time and doesn't ever get the value from the createResource function. I know that there's something I'm doing wrong, but I can't figure out what exactly.
This is an example of what I'm trying to do:
class UserDetails {
constructor(
public id: string,
public name: string,
public age: number,
public email: string,
){}
}
const emptyUserDetails = (): UserDetails => ({
id: '1234',
name: 'Test User',
age: 0,
email: 'testUser@email.com',
});
const loadUserDetailsFromAPI = async(businessId: string) => {
let res = await fetch(`users-URl/${businessId}`, {
method: 'GET',
})
.then(res => {
if (!res.ok) {
throw new Error(res.statusText)
}
if (res.status === 200) {
return res.json() as Promise<UserDetails>
}
return ;
})
.catch(err => {
console.log(err);
});
console.log("res: ", res);
return res;
}
export default function UsersPage() {
const params = useParams();
const [userDetails, setUserDetails] = createSignal<UserDetails>(emptyUserDetails());
const [userDetailsData] = createResource(params.id, loadUserDetailsFromAPI);
createEffect(() => {
console.log(userDetailsData(), userDetailsData.loading);
if (userDetailsData() != null && !userDetailsData.loading) {
setUserDetails(userDetailsData()!);
return;
}
});
return (
<div class="flex flex-col gap-3">
<span>userDetails().id</span>
<span>userDetails().name</span>
<span>userDetails().age</span>
<span>userDetails().email</span>
</div>
);
}
Finally figured out the correct way to guard against the data (user) from createResource.
From the SolidJS API:
Show can also be used with a callback that returns a null asserted accessor. Remember to only use this accessor when the condition is true or it will throw.
<Show when={state.user} fallback={<div>Loading...</div>}> {(user) => <div>{user().firstName}</div>} </Show>
Show can also be used as a way of keying blocks to a specific data model. Ex the function is re-executed whenever the user model is replaced.
import { createResource, Suspense, Show } from "solid-js";
import { useParams } from "solid-start";
interface IUserDetails{
id: string;
name: string;
images: string[];
}
class UserDetails {
id: string;
name: string;
images: string[];
constructor( {id, name, images}: IUserDetails) {
this.id = id;
this.name = name;
this.images = images;
}
}
const loadUserDetailsFromAPI = async(businessId: string) => {
let res = await fetch(`some-user-api/${businessId}`)
.catch(err => {
console.log(err);
});
if (res && res.status === 200) {
const json = res.json() as Promise<IUserDetails>
return new UserDetails(await json);
}
return;
}
export default function UsersPage() {
const params = useParams();
const [userDetails] = createResource(params.id, loadUserDetailsFromAPI);
return (<Suspense fallback= {<p> Loading...</p>}>
<Show when={userDetails()}>
{(userDetails) => <div>
<span>userDetails().id</span>
<span>userDetails().name</span>
<div>
<span>userDetails().images[0]</span>
<span>userDetails().images[1]</span>
<span>userDetails().images[2]</span>
</div>
</div>}
</Show>
</Suspense>);
}