乐闻世界logo
搜索文章和话题

How to Handle Events in Yew and What Types of Events Are Supported?

2月19日 16:24

Event Handling Mechanism in Yew

Yew provides a powerful event handling mechanism similar to React, but uses Rust's type system to ensure type safety.

Basic Event Handling

1. Click Event

rust
#[function_component(ClickHandler)] fn click_handler() -> Html { let onclick = Callback::from(|_| { web_sys::console::log_1(&"Button clicked!".into()); }); html! { <button onclick={onclick}> { "Click Me" } </button> } }

2. Input Event

rust
#[function_component(InputHandler)] fn input_handler() -> Html { let value = use_state(|| String::new()); let oninput = { let value = value.clone(); Callback::from(move |e: InputEvent| { let input: HtmlInputElement = e.target_unchecked_into(); value.set(input.value()); }) }; html! { <div> <input type="text" value={(*value).clone()} oninput={oninput} placeholder="Type something..." /> <p>{ "You typed: " }{ &*value }</p> </div> } }

3. Form Submit Event

rust
#[function_component(FormHandler)] fn form_handler() -> Html { let username = use_state(|| String::new()); let password = use_state(|| String::new()); let onsubmit = { let username = username.clone(); let password = password.clone(); Callback::from(move |e: SubmitEvent| { e.prevent_default(); web_sys::console::log_2( &"Username:".into(), &(*username).clone().into() ); }) }; let onusername_input = { let username = username.clone(); Callback::from(move |e: InputEvent| { let input: HtmlInputElement = e.target_unchecked_into(); username.set(input.value()); }) }; let onpassword_input = { let password = password.clone(); Callback::from(move |e: InputEvent| { let input: HtmlInputElement = e.target_unchecked_into(); password.set(input.value()); }) }; html! { <form onsubmit={onsubmit}> <div> <label>{ "Username:" }</label> <input type="text" value={(*username).clone()} oninput={onusername_input} /> </div> <div> <label>{ "Password:" }</label> <input type="password" value={(*password).clone()} oninput={onpassword_input} /> </div> <button type="submit">{ "Submit" }</button> </form> } }

Event Types

Yew supports multiple event types, each with corresponding Rust types:

Event TypeRust TypeCommon Use
onclickMouseEventMouse click
ondblclickMouseEventMouse double click
onmouseoverMouseEventMouse hover
onmouseoutMouseEventMouse out
oninputInputEventInput change
onchangeEventValue change
onsubmitSubmitEventForm submit
onkeydownKeyboardEventKey down
onkeyupKeyboardEventKey up
onfocusFocusEventFocus gain
onblurFocusEventFocus loss

Advanced Event Handling

1. Event Bubbling and Capturing

rust
#[function_component(EventBubbling)] fn event_bubbling() -> Html { let parent_click = Callback::from(|e: MouseEvent| { web_sys::console::log_1(&"Parent clicked".into()); e.stop_propagation(); }); let child_click = Callback::from(|_| { web_sys::console::log_1(&"Child clicked".into()); }); html! { <div onclick={parent_click} style="padding: 20px; background: lightblue;"> { "Parent" } <div onclick={child_click} style="padding: 10px; background: lightgreen;"> { "Child" } </div> </div> } }

2. Custom Events

rust
#[function_component(CustomEvent)] fn custom_event() -> Html { let on_custom = Callback::from(|data: String| { web_sys::console::log_1(&format!("Custom event received: {}", data).into()); }); html! { <ChildComponent on_custom={on_custom} /> } } #[derive(Properties, PartialEq)] pub struct ChildProps { pub on_custom: Callback<String>, } #[function_component(ChildComponent)] fn child_component(props: &ChildProps) -> Html { let trigger_custom = { let on_custom = props.on_custom.clone(); Callback::from(move |_| { on_custom.emit("Custom data from child".to_string()); }) }; html! { <button onclick={trigger_custom}> { "Trigger Custom Event" } </button> } }

3. Debouncing and Throttling

rust
use std::rc::Rc; use std::cell::RefCell; use std::time::Duration; #[function_component(DebouncedInput)] fn debounced_input() -> Html { let value = use_state(|| String::new()); let debounced_value = use_state(|| String::new()); let timeout_handle = use_mut_ref(|| None::<gloo_timers::callback::Timeout>); let oninput = { let value = value.clone(); let debounced_value = debounced_value.clone(); let timeout_handle = timeout_handle.clone(); Callback::from(move |e: InputEvent| { let input: HtmlInputElement = e.target_unchecked_into(); let new_value = input.value(); value.set(new_value.clone()); // Clear previous timer if let Some(handle) = timeout_handle.borrow_mut().take() { handle.cancel(); } // Set new debounce timer let debounced_value = debounced_value.clone(); let timeout = gloo_timers::callback::Timeout::new(300, move || { debounced_value.set(new_value); }); *timeout_handle.borrow_mut() = Some(timeout); }) }; html! { <div> <input type="text" value={(*value).clone()} oninput={oninput} placeholder="Type with debounce..." /> <p>{ "Debounced value: " }{ &*debounced_value }</p> </div> } }

Event Handling Best Practices

1. Use Callback::from to Simplify Code

rust
// Simple event handling let onclick = Callback::from(|_| { web_sys::console::log_1(&"Clicked".into()); }); // Event handling with state let onclick = { let count = count.clone(); Callback::from(move |_| count.set(*count + 1)) };

2. Avoid Unnecessary Cloning

rust
// Bad practice: clone on every render let onclick = Callback::from({ let value = value.clone(); move |_| { // use value } }); // Good practice: use Rc or references let onclick = Callback::from({ let value = Rc::clone(&value); move |_| { // use value } });

3. Type-Safe Event Handling

rust
// Use specific event types let oninput = Callback::from(|e: InputEvent| { let input: HtmlInputElement = e.target_unchecked_into(); let value = input.value(); // handle input value }); // Instead of using generic event types let oninput = Callback::from(|e: Event| { let target = e.target().unwrap(); let input: HtmlInputElement = target.unchecked_into(); // handle input value });

Common Questions

1. How to Prevent Default Behavior?

rust
let onsubmit = Callback::from(|e: SubmitEvent| { e.prevent_default(); // handle form submission });

2. How to Stop Event Bubbling?

rust
let onclick = Callback::from(|e: MouseEvent| { e.stop_propagation(); // handle click });

3. How to Get Event Target?

rust
let onclick = Callback::from(|e: MouseEvent| { let target = e.target().unwrap(); let element: HtmlElement = target.unchecked_into(); // use element });

Performance Optimization

1. Use use_callback to Avoid Repeated Creation

rust
#[function_component(OptimizedHandler)] fn optimized_handler() -> Html { let count = use_state(|| 0); let onclick = use_callback(count.clone(), |count, _| { count.set(*count + 1); }); html! { <button onclick={onclick}> { "Click me: " }{ *count } </button> } }

2. Event Delegation

rust
#[function_component(EventDelegation)] fn event_delegation() -> Html { let items = use_state(|| vec!["Item 1", "Item 2", "Item 3"]); let onclick = Callback::from(|e: MouseEvent| { let target = e.target().unwrap(); if let Some(element) = target.dyn_ref::<HtmlElement>() { if let Some(text) = element.text_content() { web_sys::console::log_1(&format!("Clicked: {}", text).into()); } } }); html! { <div onclick={onclick}> { items.iter().map(|item| { html! { <div key={item.to_string()}> { item } </div> } }).collect::<Html>() } </div> } }
标签:Yew