WASM: passing closure to a struct and then using it

So I tried to pass a Closure to a struct and using it somewhere else, however, I got an error of Closure Invoked recursively or destroyed already.

My Init function is as follow:

pub struct Core {
  pub check_resize: Rc<RefCell<Option<Closure<dyn FnMut()>>>>,
}

impl Core {
  pub fn new() -> Self {
    let mut core = Core { check_resize: Rc::new(RefCell::new(None)) };
    
    core.init_check_resize();
    core
  }

  fn init_check_resize(&mut self) {
    let callback: Rc<RefCell<Option<Closure<dyn FnMut() >>>> = Rc::new(RefCell::new(None));
    *callback.borrow_mut() = Some(Closure::new(move || {
      console::log_1(&"window got resized".into());
    }))
    self.check_resize = callback;
  } 
}

And then Somewhere in the program

impl Core {
  pub fn listen_to_resize(&self) {
        let window = window().unwrap();
        let check_resize_cb = self.check_resize.clone();
        let check_resize_cb = check_resize_cb.borrow();
        let check_resize_cb = check_resize_cb.as_ref().unwrap();
       window.add_event_listener_with_callback_and_bool("resize",check_resize_cb.as_ref().unchecked_ref(), false).unwrap();
  }

  pub fn remove_check_resize(&self) {
        let window = window().unwrap();
        let check_resize_cb = self.check_resize.clone();
        let check_resize_cb = check_resize_cb.borrow();
        let check_resize_cb = check_resize_cb.as_ref().unwrap();
window.remove_event_listener_with_callback_and_bool("resize",check_resize_cb.as_ref().unchecked_ref(), false).unwrap();
  }
}

I have also tried on calling check_resize_cb.forget() after adding the event listener but I got some ownership error.

Any help would be very much helpful since I have been fighting this for so longg!

Recreating error with Yew: Rust Playground

If the instance of Core is dropped before you cause the callback to be invoked, the actual closure on the Rust side will be deallocated and the JS won't be able to invoke it.

I'm not very familiar with Yew, but it looks to me like Core is being recreated on each render, and dropped when the render ends, which probably is not what you want.

I see, if that so, I believe replacing the position of Core::new() to fn main() should fix the problem. Unfortunately, the error is still there. As an extra step, I have also tried it with set_timeout.

I'm pretty sure your code returns from main before any event handlers have the chance to run. You aren't allowed to block the main thread on the web. Doing so freezes the page until you are done blocking and if you block too long you will get a browser popup asking the user if they want to stop the script that is running.

1 Like