Handling a Resource with type Result<Vec<_>, _> with <For ... /> #1565
-
Hello, and thanks for Leptos! I'm kind of blown away at how cool it is. I'm on v0.5.0-beta and it's great. I'm looking for an ergonomic way to use I've tried a number of methods to do this, revolving around a resource that calls an Two things I've tried. First is wrapping the For inside of a use leptos::*;
#[component]
pub fn Main() -> impl IntoView {
let (refresh, _) = create_signal(0u32);
let identities_resource = create_local_resource(
move || refresh.get(),
|_| async move {
crate::load_identities().await
},
);
let identities_view = move || {
identities_resource.with(|rt| {
match rt.as_ref() {
Ok(identities) => view! {
<For
each=|| identities.clone()
key=|t| t.id().clone()
view=|t| view! {
{t.id().clone()}
}
/>
}.into_view(),
Err(e) => view! {
<p>
{format!("Error loading identities: {}", e)}
</p>
}.into_view(),
}
})
};
view! {
<Transition fallback=move || view! {
"Loading identities"
}>
<ErrorBoundary fallback=move |errors| view! {
"ERROR"
{format!("{:?}", errors)}
}>
{identities_view}
</ErrorBoundary>
</Transition>
}
} This gives a compiler error:
And I suppose this is a bad idea anyway, because each time the resource is triggered again, it will entirely re-render the I then tried to embed the resource within the For itself (probably doesn't make sense but thought I'd try): use leptos::*;
#[component]
pub fn Main() -> impl IntoView {
let (refresh, _) = create_signal(0u32);
let identities_resource = create_local_resource(
move || refresh.get(),
|_| async move {
crate::load_identities().await
},
);
view! {
<Transition fallback=move || view! {
"Loading identities"
}>
<ErrorBoundary fallback=move |errors| view! {
"ERROR"
{format!("{:?}", errors)}
}>
<For
each=move || {
identities_resource.with(|rt| {
rt.map_err(|e| format!("{}", e))
})
}
key=|t| t.id().clone()
view=|t| view! {
{t.id().clone()}
}
/>
</ErrorBoundary>
</Transition>
}
} and that gives me an error Am I thinking about the problem wrong? What's the best way to have Thanks for your time! |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 4 replies
-
So, this is true with your current setup/the first attempt. But you could do something like create a memo that gives you the inner value or an empty list, and then use The issue with your second attempt is that |
Beta Was this translation helpful? Give feedback.
-
That makes sense, so my next question is...can this be accomplished within something like an |
Beta Was this translation helpful? Give feedback.
-
BTW I implemented a custom component for this: use crate::{
error::{Error, Result},
};
use leptos::*;
#[component]
pub fn ForResult<S, T, EF, N, KF, K, LF, LFV, FF, FFV>(
each: Resource<S, Result<Vec<T>>>,
key: KF,
view: EF,
loading: LF,
fallback: FF,
) -> impl IntoView
where S: Clone + 'static,
T: Clone + 'static,
EF: Fn(T) -> N + Copy + 'static,
N: IntoView + 'static,
KF: Fn(&T) -> K + Copy + 'static,
K: Eq + core::hash::Hash + 'static,
LF: Fn() -> LFV + Copy + 'static,
LFV: IntoView + 'static,
FF: Fn(Error) -> FFV + Copy + 'static,
FFV: IntoView + 'static,
{
let (list, set_list) = create_signal(Vec::new());
let (error, set_error) = create_signal::<Option<Error>>(None);
view! {
<Transition fallback=loading>
{move || {
each.with(|res| {
match res {
Ok(listvals) => {
set_list.set(listvals.clone());
set_error.set(None);
}
Err(e) => {
set_error.set(Some(e.clone()));
}
}
})
}}
<Show
when=move || error.get().is_none()
fallback=move || match error.get() {
Some(e) => fallback(e).into_view(),
None => view! { "Unknown error" }.into_view(),
}
>
<For
each=move || list.get()
key=key
view=view />
</Show>
</Transition>
}
} This uses my crate's custom let (refresh, _) = create_signal(0u32);
let my_resource = create_local_resource(
move || refresh.get(),
|_| async move {
let val: Result<Vec<MyValue>> = crate::load_my_value().await;
val
},
);
view! {
<ForResult
each=my_resource
loading=|| { view! { "Loading values..." }}
fallback=|e| view! { "Errrrror: " {format!("{}", e)} }
key=|v| v.id().clone()
view=move |v| view! {
<ShowValue val=v />
}
/>
} Am I off base here or is this a good solution? |
Beta Was this translation helpful? Give feedback.
ErrorBoundary doesn't wrap values, it catches
Err(_)
that's rendered. In your example, you'd want something likeas you correctly noted, this particular approach is going to re-render everything every time the resource changes, so there's no real point in
For
here. If you want to useFor
you should read the resource in a memo and feed the memo into theeach
prop.