Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create closure type; allow async event handlers in props; allow short hand event handlers #2437

Merged
merged 5 commits into from
Jun 11, 2024

Conversation

ealmloff
Copy link
Member

@ealmloff ealmloff commented May 22, 2024

Fixing EventHandler Discrepancies

This PR fixes three rough spots with EventHandler:

  1. You can't return values from EventHandler. This PR introduces a new Callback type that lets you return values. closes Tweak on* handlers to allow returning values #1936. Closes Tweak closures as props to allow easier lazy values #1968

  2. You can use async blocks in built in event handlers but not in user created event handlers. This code snippet seems like it should compile, but it doesn't in the main branch of dioxus:

TakesEventHandler { onclick: |event| async move {
    println!("{event:?}");
} }

This PR fixes that discrepancy. The docs that were added in DioxusLabs/docsite#275 should be updated in the next release

  1. If you manually create an EventHandler or accept an EventHandler through props, you currently can't pass it directly to an element. This PR fixes that issue:
let onclick = EventHandler::new(|_| {});
rsx! { button { onclick } }

Fixes #1839

Example with new features

fn app() -> Element {
    let mut todos = use_signal(String::new);
    rsx! {
        input {
            // Normal event handlers still work without explicit type annotations
            oninput: move |evt| todos.set(evt.value()),
        }
        button {
            // async event handlers are also still supported
            onclick: |event| async move {
                tokio::time::sleep(std::time::Duration::from_secs(1)).await;
                println!("{event:?}");
            },
        }

        // New! You can now use async closures for custom event handlers!
        TakesEventHandler { onclick: |event| async move {
            println!("{event:?}");
        } }
        // Or you can accept a callback that returns a value (event handlers can still have any name they want)
        TakesEventHandlerWithArg { double: move |value| value * 2 }
    }
}

#[component]
fn TakesEventHandler(onclick: EventHandler<MouseEvent>) -> Element {
    rsx! {
        button {
            // You can pass in EventHandlers directly to events
            onclick: onclick,
            "Click!"
        }
        button {
            // Or use the shorthand syntax
            onclick,
            "Click!"
        }
    }
}

#[component]
fn TakesEventHandlerWithArg(double: Callback<u32, u32>) -> Element {
    let mut count = use_signal(|| 2);
    rsx! {
        button {
            // Callbacks let you easily inject custom logic into your components
            onclick: move |_| count.set(double(count())),
            "{count}"
        }
    }
}

@ealmloff ealmloff added core relating to the core implementation of the virtualdom breaking This is a breaking change tweak Small changes to improve experience labels May 22, 2024
@jkelleyrtp jkelleyrtp merged commit d795995 into DioxusLabs:main Jun 11, 2024
9 checks passed
@ealmloff ealmloff deleted the closures branch June 11, 2024 01:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking This is a breaking change core relating to the core implementation of the virtualdom tweak Small changes to improve experience
Projects
None yet
2 participants