Self.send from another context

reasonreact

#1

Hi all
I have a App component that defined as following:

type state = {showMenuOnMobile: bool};

type action =
  | ShowMenuOnMobile(bool);

let component = ReasonReact.reducerComponent("App");

let make = _children => {
  ...component,
  initialState: () => {showMenuOnMobile: false},
  reducer: (action: action, _state: state) =>
    switch (action) {
    | ShowMenuOnMobile(toggler) =>
      ReasonReact.Update({showMenuOnMobile: !toggler})
    },
  render: self =>
    <div className="app-container">
      <Topbar
        click={
          () => self.send(ShowMenuOnMobile(self.state.showMenuOnMobile))
        }
      />
    </div>,
};

let default = ReasonReact.wrapReasonForJs(~component, _jsProps => make([||]));

and Topbar.re looks like:

type state = {empty: int};

type action =
  | Nothing;

let component = ReasonReact.reducerComponent("Topbar");

let make = (~click: 'a => unit, _children) => {
  ...component,
  initialState: () => {empty: 0},
  reducer: (_action: action, _state: state) => ReasonReact.NoUpdate,
  render: _self =>
    <div className="topbar-container">
      <section className="topbar-menu">
        <LinkRipple click cssClass="topbar-navi-menu" color="">
          ...<i className="fas fa-bars fa-2x" />
        </LinkRipple>
      </section>
    </div>,
};

and the LinkRipple.re looks as following:

let component = ReasonReact.statelessComponent("LinkRipple");

let make = (~click: 'a => unit, ~cssClass: string, ~color: string, children) => {
  /*
   * Determine the coordinates for ripple effect
   * At the end, it will execute the click function
   */

  let onLinkClicked = e => {
    let dom = External.convertToDomElement(e->ReactEvent.Mouse.target);
    let rect = Webapi.Dom.Element.getBoundingClientRect(dom);

    let x = ReactEvent.Mouse.pageX(e) - Webapi.Dom.DomRect.left(rect);
    let y = ReactEvent.Mouse.pageY(e) - Webapi.Dom.DomRect.top(rect);

    let rippleDiv =
      Webapi.Dom.Document.createElement("div", Webapi.Dom.document);
    let domTokenList = Webapi.Dom.Element.classList(rippleDiv);

    Webapi.Dom.DomTo`Preformatted text`kenList.add("ripple", domTokenList);
    Webapi.Dom.Element.setAttribute(
      "style",
      "top:" ++ string_of_int(y) ++ "px; left:" ++ string_of_int(x) ++ "px;",
      rippleDiv,
    );
    Webapi.Dom.Element.appendChild(rippleDiv, dom);

    click(()); 

    Js.Global.setTimeout(
      () => Webapi.Dom.Element.removeChild(rippleDiv, dom) |> ignore,
      500,
    )
    |> ignore;
  };

  {
    ...component,
    render: _self =>
      <a onClick=onLinkClicked className=cssClass> children </a>,
  };
}; 

The page looks like:

The bulk is the Topbar and bar(with the 3 strip) is LinkRipple. When I clicked the first time on the LinkRipple, the ripple effect does not appear as expected. Further clicks, the ripple effect appears as expected. The click property function, that will be executed in the onLinkClicked function on the LinkRipple cause the problem. But I could not figure why?

You can find the code on https://github.com/khinkali/cockpit and with npm run develop to run the server. Please resize the screen to mobile or table size, then the bar will appear.

Thanks