Recently with React 1.16.7 alpha react announced it would be releasing “hooks” to allow you to use state outside of a class component (hooks intro). This has large implications for DRY coding and reusing stateful logic. Before when you had components that overlapped functionalities you could define getters/setters which could clunkily fit into each component. This post won’t be about hooks but will be a simple use case of extracting logic from a common library.
Modals and popovers
The first thought that came to me when I heard about this is reusing one of the most common react component’s functionalities – modals and popovers. Whenever I am introducing a custom modal/dropdown/popover I always have relied on one of the many libraries for handling clicking outside of my components scope (usually react-onclickoutside because the 0 dependencies). Recently I have decided to take it into my own hands and just implement it myself using document event listeners a reference to the modal content (source: article). But I thought I could take this time to implement this using these brand new react hooks.
I am going to do a comparison between two applications with the exact same purpose: Render a button to open a modal – and clicking anywhere not inside the modal should close the modal.
Base modal app
It’s important to note the size/complexity of not only the component we are focusing on but the controlling component above the modal where we are controlling whether to render the modal or not.
I pass a function `setIsOpen` as a prop to the modal component, and conditionally render it using `isModalOpen`. From the library `react-onclickoutside` I defined the function `handleClickOutside` which calls the `setIsOpen` function.
Since we don’t have to define a `constructor`, or `handleClickOutside` we can use functional react components. We create a hook using `useState` to control `isOpen` and create a handler `setIsOpen`. In the Modal component, we use `useRef` to create and access a ref for the modal content and determine if the click event was contained inside the modal. `useEffect` is defined as the custom `useClickOutside` hook.
And the custom `useClickOutside` hook:
Just takes in a ref and the callback that is utilized when the click isn’t contained inside the ref (`onModalClose`). For our case setting the modal to close, but it could be anything since it is just a callback function that is passed in as an argument to the hook.
To me, this seems like a positive improvement for separating common logic. Only time will tell how widely adopted this approach of using hooks to reuse stateful component logic will become. In my opinion, it sure is nice reusing the same hook for any component that needs to detect clicks outside of its scope.