DioxusLabs / dioxus

Fullstack app framework for web, desktop, mobile, and more.
https://dioxuslabs.com
Apache License 2.0
20.14k stars 772 forks source link

issue: Counterintuitive spread of props #1870

Open marc2332 opened 7 months ago

marc2332 commented 7 months ago

Currently, spreaded props of Components will take over any children that you pass later, this aligns with Rust's way of spreading structs, but it might be counterintuitive for some users when used in Dioxus

Example:

#[component]
fn Button(children: Element, whatever: bool) -> Element {
    rsx!(
       {children}
    )
}

fn app() -> Element {
    rsx!(
        Button {
           ..ButtonProps {
              whatever: true,
              children: None
           },
           p { "I don't exist :(" } // This won't exist
        }
    )
}

Workaround:

fn app() -> Element {
    rsx!(
        Button {
           children: rsx!(
              p { "I exist :)" } // This will exist
           ),
           ..ButtonProps {
              whatever: true,
              children: None
           }
        }
    )
}
jkelleyrtp commented 1 month ago

To solve this we'll override the manual props children with the explicit children since that seems like the most sensible/consistent behavior.

ealmloff commented 1 week ago

I think the way we spread props is fundamentally flawed. It doesn't go through the builder, so none of the prop attributes are applied. Which means you can't spread into something with props(extends = ...) or props(into)

The into for string doesn't get called when you spread which breaks this example:

fn testing() -> Element {
    rsx! {
        Component { a: "hello", ..ComponentProps { a: "hello 123".to_string(), b: "world".to_string() } }
    }
}

#[component]
fn Component(a: String, b: String) -> Element {
    rsx! {
        div { "{a}" }
        div { "{b}" }
    }
}