Proper way to handle events within stateless components?


#1

Hi there,

I’m working on an app where the root component contains the app state and the main reducer. This seems similar to what you get with React + Redux in JS.

There is one issue though. With ReactJS/Redux I could just pass the dispatch function down the chain via props in order to let stateless components fire actions via onClick, onChange, etc., e.g.:

const ToggleButton = pure((props: Props) => {

  return (
    <button
      type="button"
      onClick={() => props.dispatch(toggleNavMenu())}
>

In ReasonReact I can’t get this to work. I tried passing self.send via props but it left me with an error. I read somewhere that I should use self.handle() instead, but that’s leaving me with bloated interfaces like this one:

<Search
  onColumnDropdownChange=(self.handle(Uni.columnDropdownChange))
  onOperatorDropdownChange=(self.handle(Uni.operatorDropdownChange))
  onAdvancedSearchToggle=(self.handle(advancedSearchToggle))
  onInputChange=(self.handle(Uni.inputChange))
  onInputKeyDown=(self.handle(Uni.inputKeyDown))
  advancedSearchState=self.state.searchState.advancedSearch
  columns=Messages.columns
/>

Compared to ReactJS/Redux, where I could use this:

<Search
  dispatch=props.dispatch
  advancedSearchState=state.searchState.advancedSearch
  columns=messages.columns
/>

I wonder if I’m doing something wrong here? How do you guys handle this? Please let me know :slight_smile:


#2

You can pass down a function action => self.send(action) as the dispatch function, but you’ll have to make sure that the action type is defined in a place where both the child component and the current component can access it without creating an import loop


#3

Your solution works like a charm! Thanks! :smiley:

Here is an example (in case anyone likes to know):

Create a stateless component that takes the send function as an argument:

module Search = {
  let component = R.statelessComponent("Search");
  let make = (~advancedSearchState, ~columns, ~send, _children) => {
    ...component,
    render: _self =>
        /* ... */
        <a href="#" onClick=(event => send(AdvancedSearchOn(true)))>
          (R.string(text))
        </a>;
        /* ... */

The parent component can pass the send function to the child component:

<Search
   advancedSearchState=self.state.searchState.advancedSearch
   columns=Messages.columns
   send=(action => self.send(action))
/>