yew-hooks icon indicating copy to clipboard operation
yew-hooks copied to clipboard

Making the `use_async` a bit more ergonomic

Open ctron opened this issue 2 years ago • 3 comments

I really like this project, especially the use_async hook.

However, evaluating the state when rendering feels a bit verbose. It feels to me as if this could be improved a bit, using an enum.

If you are interested, I would try to come up with a PR, as basis for further refining it. Trying to keep the default API intact.

ctron avatar Apr 12 '23 08:04 ctron

hi, the design of separate fields for loading/data/error is a bit like SWR lib of js world, data and error could even co-exist for cache/user-friendly reasons, maybe we could not reduce them to a enum like Result<Data, Error>.

jetli avatar Apr 12 '23 15:04 jetli

Right now evaluating the state looks a bit like this:

#[function_component(EvalView)]
pub fn eval_view(props: &EvalViewProps) -> Html {
    match &props.eval {
        UseAsyncState { loading: true, .. } => {
            html!("Loading...")
        }
        UseAsyncState {
            error: Some(err), ..
        } => {
            html!(format!("Failed: {err}"))
        }
        UseAsyncState {
            data: Some(result), ..
        } => {
            html!(
                <ResultView result={result.clone()}/>
            )
        }
        _ => html!(""),
    }
}

Which isn't optimal IMHO. I think this could be changed into something like:

#[function_component(EvalView)]
pub fn eval_view(props: &EvalViewProps) -> Html {
    match &props.eval {
        UseAsyncState::Loading => {
            html!("Loading...")
        }
        UseAsyncState::Err(err) => {
            html!(format!("Failed: {err}"))
        }
        UseAsyncState::Ok(result) => {
            html!(
                <ResultView result={result.clone()}/>
            )
        }
    }
}

Which feels a bit more natural to me. I am not sure in which case one would have all three values together. Maybe I don't understand the idea having having both data and error at the same time.

ctron avatar Apr 12 '23 16:04 ctron

I went ahead, trying to create an example of what I had in mind, something like:

#[derive(PartialEq, Eq)]
pub enum UseAsyncState<T, E> {
    /// Operation has not been started yet
    Pending,
    /// Operation is running
    Loading,
    /// Operation is complete
    Ready(Result<T, E>),
}

While updating the code I think I ran into what you had in mind with "caching", when updating the example.

When the state changes to "loading" again, the old data is still available. So data can be shown, while loading new.

I personally am not a fan of this, as it shows stale data. Maybe the solution could be to create a second version of use_async, which doesn't have this have this behavior. And maybe one implementation can be built on the other.

ctron avatar Apr 13 '23 07:04 ctron