dioxus icon indicating copy to clipboard operation
dioxus copied to clipboard

Add `async_set` for `UseState` type

Open MuhannadAlrusayni opened this issue 3 years ago • 2 comments

Specific Demand

currently to set new value in state asynchronously, we need to spawn Future using cx.spawn, and since this quite common thing, I find it a bit verbose, and I thnk we can do better.

currently I do something like this:

fn MyComponent(cx: Scope) -> Element {
    let response: &UseState<Option<String>> = use_state(&cx, || None);

    cx.render(rsx!(
        button {
            // Note the verbosity of the current API
            onclick: move |_| {
                let response = response.clone();
                cx.spawn(async move {
                    let value = match fetch("my-api.org").await.ok() {
                        Some(res) => res.text().await.ok(),
                        None => None,
                    };
                    response.set(value)
                })
            }
        }
        response.get().map(|res| rsx!(cx, p { "respones: {res}" }))
    ))
}

Implement Suggestion

I would like to request adding method async_set for UseState<T> type, so I can easily set a new state asynchronously.

and example above would be:

fn MyComponent(cx: Scope) -> Element {
    let response: &UseState<Option<String>> = use_state(&cx, || None);

    cx.render(rsx!(
        button {
            // I think this is way more ergonomic
            onclick: move |_| response.async_set(async { fetch("my-api.org").await.ok() }),
        }
        response.get().map(|res| rsx!(cx, p { "respones: {res}" }))
    ))
}

I'm currently using extension trait pattern to add this to UseState<T>:

pub trait UseStateExt<T> {
    fn async_set(&self, cx: &ScopeState, future: impl Future<Output = T> + 'static);
}

impl<T> UseStateExt<T> for UseState<T> {
    fn async_set(&self, cx: &ScopeState, future: impl Future<Output = T> + 'static) {
        let my_state = self.clone();
        cx.spawn(async move { my_state.set(future.await) })
    }
}

regarding the method name, I have no strong opinion as long as it reflect what it does. and I think we might need async_modify(..) I don't have use case for it yet. but I think we will eventually need it, and it make sense to have async variant of modify(..) method.

MuhannadAlrusayni avatar Apr 25 '22 22:04 MuhannadAlrusayni

I think this is great!

I also like the code you already have written, so I can just use that as basis for a PR.

I will probably name the method to be set_async, just so you see both when you use your IDE autocomplete with set.

jkelleyrtp avatar May 02 '22 16:05 jkelleyrtp

Then I think I'll go and submit a PR for this if you don't mind :D

MuhannadAlrusayni avatar May 04 '22 00:05 MuhannadAlrusayni

Now that we've removed scopes and stuff, we don't need this feature anymore :-)

Closed by #1791

jkelleyrtp avatar Feb 23 '24 22:02 jkelleyrtp