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?

Alan R. Soares
  • 1,735
  • 1
  • 15
  • 19

2 Answers2

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>,
};
Nick Retallack
  • 18,986
  • 17
  • 92
  • 114
Yawar
  • 11,272
  • 4
  • 48
  • 80
  • How do you access properties on the event? Being new to Reasonml, and reading [this](https://github.com/reasonml-community/bs-webapi-incubator/blob/master/src/dom/events/KeyboardEventRe.re), I'd expect to access `event.key`, but I can't. How am I to understand that file? –  Jul 26 '18 at 10:42
  • @GormCasper you can use `key` as a function, e.g. `let handleKey = evt => Js.log2("Key pressed:", Dom.KeyboardEvent.key(evt));` – Yawar Jul 26 '18 at 13:25
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";
Alan R. Soares
  • 1,735
  • 1
  • 15
  • 19
  • Ah, I see that works because these two functions are available in the browser global namespace. – Yawar Jun 29 '18 at 04:13
  • This, listening for `keydown` combined with `ReactEventRe.Keyboard.key(event)` to get, say, the key that was pressed –  Jul 26 '18 at 11:38