Trying to use `click` Event Closures in `web_sys`

I have this struct:

#[wasm_bindgen]
pub struct App {
	animation_id: i32,
	game: Game,
	canvas: HtmlCanvasElement,
	context: CanvasRenderingContext2d,
	images: HashMap<ImageKey, HtmlImageElement>,
}

I'm trying to attach a closure as a click event listener to the canvas member. This closure needs to call mutable methods on the game member, but I'm not sure how to go about that.

Here's what I'm trying to do:

	fn attach_event_listeners(app: &App) {
		{
			let el = app.canvas.clone();

			let cb = Closure::<dyn FnMut(_)>::new(move |event: MouseEvent| {
				let rect = el.get_bounding_client_rect();
				let x = event.client_x() - rect.left() as i32;
				let y = event.client_y() - rect.top() as i32;
				let x_tile = (x / PIXELS_PER_CELL as i32) as i8;
				let y_tile = (y / PIXELS_PER_CELL as i32) as i8;

				let index = app.game.get_cell_index(x_tile, y_tile).unwrap(); /* PROBLEM */
				let cell = game.as_mut().unwrap().cells().get(index).unwrap(); /* PROBLEM */

				app.game.reveal_cell(x_tile, y_tile).unwrap(); /* PROBLEM */

				event.prevent_default();
			});

			app.canvas
				.add_event_listener_with_callback("click", cb.as_ref().unchecked_ref())
				.unwrap();

			cb.forget();
		}
	}

This obviously doesn't work because these closures use the move keyword to move ownership. I've been looking through the examples in the web_sys crate's repo, and it looks like I might need to wrap it in Rc and Cell smart pointers as an escape hatch to get around some of the borrowing rules in this case. Is this correct?

I get the feeling that I'm going about this wrong.

EDIT: I think I got it after another day of researching, and re-reading the Rust book's section on Rc. I need to get better at Cell<T> and RefCell<T>. Regular references and Box<T> (mutable and immutable) make a lot of sense. Rc makes sense too, but it's difficult to understand if I'm using them correctly in practice. Cell<T> and RefCell<T> concern me because they seem to effectively nullify core borrow-checking principles as safe wrappers around unsafe implementations. That said, it seems like a useful escape hatch in this case because of the Rust-to-JS/DOM interop that I'm trying to do.