使用 Yew 回调作为wasm_bindgen闭包

Using a Yew Callback as a wasm_bindgen Closure

提问人:Athan Clark 提问时间:7/13/2022 更新时间:7/13/2022 访问量:689

问:

此问题是为 Yew v0.19 编写的

异步外部 JavaScript 函数可以在 Rust 中使用到 Closures,作为传入的函数:


#[wasm_bindgen]
extern "C" {
    fn setInterval(closure: &Closure<dyn FnMut()>, time: u32) -> i32;
}

// ...

let cb = Closure::new(|| {
    log("interval elapsed!");
});

let interval_id = setInterval(&cb, 1_000);

这对于一个迂腐的例子来说很好,但有一个关键的要求——应用的函数需要有生命周期。同样,对于 Yew 应用程序,自发响应的完美机制是枚举,并让它 .但是,(发出消息)中的机制没有静态生存期。Closure'staticMessageupdate()Modellink()Context

在理想情况下,提交给闭包的值可以作为 Yew 组件消息应用:

struct Model {
    thing: Option<JsValue>,
}

enum Msg {
    GotThing(JsValue),
}

#[wasm_bindgen]
extern "C" {
    fn createThing(closure: &Closure<dyn FnMut(JsValue) -> ());
}

impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_ctx: &Context<Self>) -> Self {
        Model {
            thing: None, // initial value
        }
    }

    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
        match msg {
            Msg::GotThing(x) => { // handle the message
                self.thing = Some(x);
                true
            },
        }
    }

    fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
        if first_render {
            let cb: Box<dyn FnMut(JsValue) -> ()> = Box::new(|x| {
                // try and issue the message
                ctx.link().send_message(Msg::GotThing(x));
                // ^ doesn't have a `'static` lifetime! Won't compile
            });
            createThing(Closure::wrap(&cb));
        }
    }

    // fn view() ... omitted, not relevant
}

我想知道是否有办法将 a 转换为 ,或者是否有更好、更规范的方法可以做到这一点,请纠正我。CallbackClosure

我的另一个想法是使用某种静态定义的队列(这并不安全,因为它是一个可变的静态变量),但它可以用作传递给之间的中间数据类型,并且可以在组件内调度消息。ClosurecreateThing

也许有一种与我忽略的 Yew 组件交互的外部方式?我不确定如何解决这个问题。实现这一目标的最正确方法是什么?

rust 回调 闭包 wasm-bindgen yew

评论

0赞 SirVer 10/25/2022
很好的问题 - 我目前正在为同样的问题而苦苦挣扎。你有没有想过这一点?
0赞 jq170727 1/23/2023
这可以帮助我解决类似的问题 - 从 JS 调用 Yew 回调来更改 Yew 路由。
0赞 jq170727 1/23/2023
看起来这个来自 craftyc0der 的要点可能提供了一种方法。

答: 暂无答案