Reputation: 8086
In Yew, I am attempting to bind a callback to the window resize event, triggering a Msg::Resize
update. I have encountered: E0631 Type mismatch in closure arguments.`
Expanded version of the code can be found here:
This is the minimalist test case:
use gloo_console::log;
use gloo_events::EventListener;
use yew::prelude::*;
pub struct CanvasQuestion {}
pub enum Msg { Resize }
impl Component for CanvasQuestion {
type Message = Msg;
type Properties = ();
fn create(_ctx: &Context<Self>) -> Self {
Self { }
}
fn view(&self, _ctx: &Context<Self>) -> Html {
html! { <canvas id="canvas"/> }
}
fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
if first_render {
// WORKS
ctx.link().send_message(Msg::Resize);
// found signature of `fn(yew::Event)
// let on_window_resize = |_event: Event| { // BROKEN
let on_window_resize = |_event: &Event| { // WORKS
ctx.link().send_message(Msg::Resize);
};
// expected signature of `for<'r> fn(&'r yew::Event)
EventListener::new( &web_sys::window().unwrap(),
"resize", on_window_resize );
}
}
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::Resize => { true } // rerender
}
}
}
Update
Replacing on_window_resize = |_event: Event|
with on_window_resize = |_event: &Event|
fixes the below errors
error[E0631]: type mismatch in closure arguments
--> src/components/canvas_question.rs:68:43
|
64 | let on_window_resize = |_event: Event| {
| --------------- found signature of `fn(yew::Event) -> _`
...
67 | EventListener::new( &web_sys::window().unwrap(),
| ------------------ required by a bound introduced by this call
68 | "resize", on_window_resize );
| ^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r yew::Event) -> _`
|
note: required by a bound in `EventListener::new`
--> /home/jamie/.cargo/registry/src/github.com-1ecc6299db9ec823/gloo-events-0.1.2/src/lib.rs:338:12
|
338 | F: FnMut(&Event) + 'static,
| ^^^^^^^^^^^^^ required by this bound in `EventListener::new`
But exposes rust lifetime issues trying to access ctx.link()
from inside the closure.
error[E0521]: borrowed data escapes outside of associated function
--> src/components/fractal.rs:70:28
|
51 | fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
| --- - let's call the lifetime of this reference `'1`
| |
| `ctx` is a reference that is only valid in the associated function body
...
70 | let listener = EventListener::new( &web_sys::window().unwrap(),
| ____________________________^
71 | | "resize", on_window_resize );
| | ^
| | |
| |___________________________________________________________________________`ctx` escapes the associated function body here
| argument requires that `'1` must outlive `'static`
ctx: Context
?ctx.link()
the best way to trigger internal message passing?self.update(Msg::Resize)
directly instead?ctx.link()
need to be stored as self.link
in the CanvasQuestion struct?on_window_resize()
function?Upvotes: 0
Views: 206
Reputation: 8086
@Dogbert's comment of passing a reference to |_event: &Event|
fixed error[E0631]: type mismatch in closure arguments
, butr this turned out not to be needed in the final solution.
RTFM discovered the manual had the code pattern I needed
This uses the move keyword to pass ctx.link().callback()
into the closure by value rather than reference, thus avoiding the lifetimes issue.
pub struct CanvasQuestion {
listener: Option<EventListener>,
}
impl Component for CanvasQuestion {
fn create(_ctx: &Context<Self>) -> Self {
Self {
listener: None,
}
}
fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
if first_render {
ctx.link().send_message(Msg::Resize);
let onresize = ctx.link().callback(|_: Event| Msg::Resize);
let listener = EventListener::new(
&web_sys::window().unwrap(),
"resize",
move |e| onresize.emit(e.clone())
);
self.listener = Some(listener);
}
}
}
Upvotes: 1