Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Capturing a click outside a Reason-React Component
Sebastian Kurpiel
Sebastian Kurpiel

Posted on • Edited on

     

Capturing a click outside a Reason-React Component

I found myself the other day trying to build a dropdown component in Reason that on outside click would close the menu if opened.
Alt Text

The only example I could find of this was in Reason fromGlennSL and it was a bit outdated since it was written in 2018, before hooks were fully implemented into reason. The code below is an updated version using hooks, it requires thebs-dependency ofbs-webapi so make sure to add that before you use it.

[@genType"OnClickOutside"][@react.component]letmake=(~onOutsideClick,~children)=>{letoutsideContainer=React.useRef(Js.Nullable.null);React.useEffect0(()=>{openWebapi.Dom;letonClick=e=>{lettarget=MouseEvent.target(e);letoutsideDiv=Belt.Option.getExn(Js.Nullable.toOption(React.Ref.current(outsideContainer)),);lettargetElement=EventTarget.unsafeAsElement(target);if(!Element.contains(targetElement,outsideDiv)){onOutsideClick();};};Document.addClickEventListener(onClick,document);Some(()=>Document.removeClickEventListener(onClick,document));});<divref={outsideContainer->ReactDOMRe.Ref.domRef}>children</div>;};
Enter fullscreen modeExit fullscreen mode

The logic breakdown:

  • wrap the component in a div with a ref
  • add an event listener for onClick
  • in that onClick function check whether the element clicked contains the div with the ref, if it does then the click is inside the div. If not then the click is outside of the div.
  • If the click is outside of the container then do whatever you need it to(in this case above, close the menu)

In the use case above we wrap our select component in theOnClickOutside and onOutsideClick close the dropdown menu container like so;

let(visible,setVisibility)=React.useState(()=>false);<OnClickOutsideonOutsideClick={_e=>setVisibility(_=>false)}><Select.Buttontoggled=visibleonClick={_e=>setVisibility(_=>!visible)}/><Select.Listnametoggled=visible/></OnClickOutside>
Enter fullscreen modeExit fullscreen mode

If you enjoy writing Reason and would like to write more of it, you're in luck. Draftbit ishiring, we're a no-code tool that let's users build cross-platform apps and we're built mostly in reason! Check us out!

UPDATE:

I was experiencing some state issues with the trigger so I added an extra useEffect to fix this.

[@genType "OverlayTrigger"][@react.component]let make = (~onClick, ~children) => {  let outsideContainer = React.useRef(Js.Nullable.null);  open Webapi.Dom;  let onClickHandler = event => {    let target = MouseEvent.target(event);    let outsideDiv =      Belt.Option.getExn(        Js.Nullable.toOption(React.Ref.current(outsideContainer)),      );    let targetElement = EventTarget.unsafeAsElement(target);    if (!Element.contains(targetElement, outsideDiv)) {      onClick();    };  };  React.useEffect2(    () => {      Document.addMouseDownEventListener(onClickHandler, document);      Some(        () => Document.removeMouseDownEventListener(onClickHandler, document),      );    },    (onClick, React.Ref.current(outsideContainer)),  );  <div    className="cursor-pointer w-full"    ref={outsideContainer->ReactDOMRe.Ref.domRef}>    children  </div>;};
Enter fullscreen modeExit fullscreen mode

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

I'm a web dev that just started his professional career less than a year ago.
  • Location
    Chicago
  • Education
    Loyola University Chicago
  • Work
    Junior Dev
  • Joined

More fromSebastian Kurpiel

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp