How to handle global DOM events in ReasonML/ReasonReact?
Asked Answered
B

2

5

What's the most idiomatic way of listening/handling global DOM events in ReasonML.

I'm building a ReasonReact version of the 2048 game where I need to listen for keyboard events.

In a standard JS/React app I'd have a component with a componentDidMount lifecycle method where I would listen to the event with document.addEventListener("keypress", [my_event_handler]) and unlisten to the same on componentWillUnmount with document.removeEventListener("keypress", [my_event_handler]).

What's the most idiomatic way of accessing document.(addEventListener/removeEventListener) in Reason/ReasonReact?

Bevus answered 27/6, 2018 at 22:51 Comment(0)
B
6

You can do pretty much the same thing in ReasonReact–it supports the didMount and willUnmount lifecycle methods, which correspond to their ReactJS namesakes: https://reasonml.github.io/reason-react/docs/en/lifecycles.html

To add and remove event listeners, you can use @glennsl's excellent bs-webapi package: https://redex.github.io/package/bs-webapi

Here are some examples of adding and removing event listeners: https://github.com/reasonml-community/bs-webapi-incubator/blob/24cee2500b9c98355a14896fa9fc4ceb8a3e2258/tests/dom/events/eventTarget_test.re

Putting it all together, you could have a component like this:

/* src/components/MyComponent.re */
let document = Webapi.Dom.Document.asEventTarget(Webapi.Dom.document);
let handleKey = _ => Js.log("Key pressed");
let component = ReasonReact.statelessComponent("MyComponent");
let make = _children => {
  ...component,
  didMount: _self =>
    Webapi.Dom.EventTarget.addEventListener("keypress", handleKey, document),
  willUnmount: _self =>
    Webapi.Dom.EventTarget.removeEventListener("keypress", handleKey, document),
  render: _self => <p> (ReasonReact.string("Hello")) </p>,
};
Bonanno answered 28/6, 2018 at 2:8 Comment(2)
How do you access properties on the event? Being new to Reasonml, and reading this, I'd expect to access event.key, but I can't. How am I to understand that file?Aubervilliers
@GormCasper you can use key as a function, e.g. let handleKey = evt => Js.log2("Key pressed:", Dom.KeyboardEvent.key(evt));Bonanno
B
1

I ended up writing my own bindings to addEventListener and removeEventListener:

[@bs.val]
external add_keyboard_event_listener :
  (string, ReactEventRe.Keyboard.t => unit) => unit =
  "addEventListener";

[@bs.val]
external remove_keyboard_event_listener :
  (string, ReactEventRe.Keyboard.t => unit) => unit =
  "removeEventListener";
Bevus answered 28/6, 2018 at 23:24 Comment(2)
Ah, I see that works because these two functions are available in the browser global namespace.Bonanno
This, listening for keydown combined with ReactEventRe.Keyboard.key(event) to get, say, the key that was pressedAubervilliers

© 2022 - 2024 — McMap. All rights reserved.