How to reuse a Yew callback for multiple elements

97 views Asked by At

I want to use the callback onclick for both buttons without creating a clone of it like this:

let onclick2 = onclick.clone()

I tried using onclick.clone().emit() but the 'use of moved value' error still persists with this.

#[function_component]
pub fn Navbar() -> Html {
    let navigator = use_navigator().unwrap();
    let onclick = Callback::from(move |route: &Route| navigator.push(route));
    html! {
        <nav class="bg-indigo-700 flex justify-between items-center mx-auto max-w p-3">
            <div>
                <h1 class="text-gray-50 font-bold text-2xl">{"Arithmetic Booster"}</h1>
            </div>
            <div class="flex space-x-2">
                <button class="text-gray-50 bg-indigo-600 p-2 rounded-md" onclick={ move |_| {onclick.emit(&Route::Home)}}>{"Play"}</button>
                <button class="text-gray-50 bg-indigo-600 p-2 rounded-md" onclick={ move |_| {onclick.emit(&Route::Scores)}}>{"Scores"}</button>
                <button class="text-gray-50 bg-red-600 p-2 rounded-md">{"Quit"}</button>
            </div>
        </nav>
    }
}

Is there anyway I can reuse the callback without creating a clone and assigning it to the second button?

1

There are 1 answers

1
Chayim Friedman On BEST ANSWER

You can introduce a new scope in the closure's declaration, this is a common idiom:

#[function_component]
pub fn Navbar() -> Html {
    let navigator = use_navigator().unwrap();
    let onclick = Callback::from(move |route: &Route| navigator.push(route));
    html! {
        <nav class="bg-indigo-700 flex justify-between items-center mx-auto max-w p-3">
            <div>
                <h1 class="text-gray-50 font-bold text-2xl">{"Arithmetic Booster"}</h1>
            </div>
            <div class="flex space-x-2">
                <button class="text-gray-50 bg-indigo-600 p-2 rounded-md"
                    onclick={
                        let onclick = onclick.clone();
                        move |_| onclick.emit(&Route::Home)
                    }>{"Play"}</button>
                <button class="text-gray-50 bg-indigo-600 p-2 rounded-md"
                    onclick={ move |_| onclick.emit(&Route::Scores) }>{"Scores"}</button>
                <button class="text-gray-50 bg-red-600 p-2 rounded-md">{"Quit"}</button>
            </div>
        </nav>
    }
}