yewstack / yew

Rust / Wasm framework for creating reliable and efficient web applications
https://yew.rs
Apache License 2.0
30.9k stars 1.43k forks source link

[Feature]: Provide a `Default` trait implementation for the `UseStateHandle` struct #3597

Open wiseaidev opened 10 months ago

wiseaidev commented 10 months ago

Problem:

While working on yew-alert, I noticed that std::default::Default is not implemented for yew::UseStateHandle. This could be beneficial when implementing the Default trait for a component's Props. For instance, in the case of AlertProps, it would resemble:

impl Default for AlertProps {
    fn default() -> Self {
        AlertProps {
            message: Default::default(),
            timeout: Default::default(),
            show_alert: Default::default(), // Error: the trait `std::default::Default` is not implemented for `yew::UseStateHandle<bool>`
            // show_alert: use_state(|| true), // <--- This thing should work, but it is returning opaque type something
            // ...snip...
        }
    }
}

This functionality is useful for allowing users to initialize the props struct by only passing some of the props values, with the others set to default, like so:

let props = AlertProps {
    message: "Hello",
    ..AlertProps::default()
}

And then consume it in a component like so:

html!{
    <Alert ..props />
}

The same should apply to the prop_or attribute:

pub struct AlertProps {
    // ...snip...
    /// State handle to control the visibility of the alert.
    #[prop_or(use_state(|| true)]
    pub show_alert: UseStateHandle<bool>,
    // ...snip...
html!{
    <Alert message="Hello" />
}

Steps To Reproduce:

Attempt to implement Default for props containing a UseStateHandle field type.

Expected Behavior:

The UseStateHandle struct should have an implementation of the Default trait.

Environment:

Questionnaire:

[!NOTE] This feature is useful to adhere to the DRY principle and decouple logic from UI as shown in this example.

dospore commented 10 months ago

This seems like a nice first issue, im open to picking this up if you guys agree. Will probably require some generics and working with traits but am open to the challenge

dospore commented 10 months ago

@wiseaidev after having a look it seems pretty complex. We could make it work by giving an empty closure as the dispatch function but would not achieve much since you can just do that on your side instead and pass a default show_alert closure instead of a UseStateHandler. The opaque type comes from the hook macro which allows the reducers to access the HookContext which gets created when the function component is created. Since this is props im not sure that can be instantiated before then and is why hooks must be called inside the fc.

The usecase might not be important enough for its complexity (if it is complex). It feels like there might be a way to do it but will have to wait for more guidance from someone a bit more experience with the codebase.