UNPKG

reason-react-brunch

Version:

React bindings for Reason, modified to work with brunch and bucklescript

109 lines (78 loc) 3.88 kB
--- title: Callback Handlers --- This section describes how ReactJS' `<div onClick={this.handleClick} />` pattern translates into ReasonReact. ## Callback Without State Update Two scenarios. ### Not Reading Into `self` _Reminder: `self` is ReasonReact's `this`. It's a record that contains things like `state`, `send` and others._ If you're just forwarding a callback prop onto your child, you'd do exactly the same thing you'd have done in ReactJS: ```reason let component = ...; let make = (~name, ~onClick, _children) => { ...component, render: (self) => <button onClick=onClick /> }; ``` No surprise here. Since Reason's JSX has [punning syntax](https://reasonml.github.io/docs/en/jsx.html), that `button` will format into `<button onClick />`. Similarly, to pre-process a value before sending it back to the component's owner: ```reason let component = ...; let make = (~name, ~onClick, _children) => { let click = (event) => onClick(name); /* pass the name string up to the owner */ { ...component, render: (self) => <button onClick=click /> } }; ``` ### Reading Into `self` To access `state`, `send` and the other items in `self` from a callback, you **need** to wrap the callback in an extra layer called `self.handle`: ```reason let component = ...; let make = (~name, ~onClick, _children) => { let click = (event, self) => { onClick(event); Js.log(self.state); }; { ...component, initialState: ..., render: (self) => <button onClick={self.handle(click)} /> } }; ``` **Note** how your `click` callback now takes the extra argument `self`. Formally, `self.handle` expects a callback that - accepts the **single** payload you'd normally directly pass to e.g. `handleClick`, - plus the argument `self`, - returns "nothing" (aka, `()`, aka, `unit`). **Note 2**: sometimes you might be forwarding `handle` to some helper functions. Pass the whole `self` instead and **annotate it**. This avoids a complex `self` record type behavior. See [Record Field `send`/`handle` Not Found](record-field-send-handle-not-found.md). #### Explanation In reality, `self.handle` is just a regular function accepting two arguments, the first being the callback in question, and the second one being the payload that's intended to be passed to the callback. Get it? Through Reason's natural language-level currying, we usually only ask you to pass the first argument. This returns a new function that takes in the second argument and executes the function body. The second argument being passed by the caller, aka the component you're rendering! #### Callback Receiving Multiple Arguments Sometimes, the component you're calling is from JavaScript (using the [ReasonReact<->ReactJS interop](interop.md)), and its callback prop asks you to pass a callback that receives more than one argument. In ReactJS, it'd look like: ```javascript handleSubmit: function(username, password, event) { this.setState(...) } ... <MyForm onUserClickedSubmit={this.handleSubmit} /> ``` You cannot write such `handleSubmit` in ReasonReact, as `handle` expects to wrap around a function that only takes **one** argument. Here's the workaround: ```reason let handleSubmitEscapeHatch = (username, password, event) => self.handle( (tupleOfThreeItems, self) => doSomething(tupleOfThreeItems, self), (username, password, event), ); ... <MyForm onUserClickedSubmit=(handleSubmitEscapeHatch) /> ``` Basically, you write a normal callback that: - takes those many arguments from the JS component callback prop, - packs them into a tuple and call `self.handle`, - pass to `handle` the usual function that expects a single argument, - finish calling `self.handle` by passing the tuple directly yourself. ## Callback With State Update You can't update state in `self.handle`; you need to use `self.send` instead. See the next section.