Thành's Blog

useClickOutside

March 30, 2019 • 1 mins

Snippet

import React from 'react'

export const useClickOutside = <T extends HTMLElement>(
  handler: (event: Event) => void,
) => {
  const ref = React.createRef<T>()
  React.useEffect(() => {
    const listener = (event: Event) => {
      const target = event.target as HTMLElement
      if (!ref.current || ref.current.contains(target)) {
        return
      }

      handler(event)
    }

    document.addEventListener('mousedown', listener)
    document.addEventListener('touchstart', listener)
    return () => {
      document.removeEventListener('mousedown', listener)
      document.removeEventListener('touchstart', listener)
    }
  }, [handler])

  return ref
}

Usage

import React from 'react'
import { useClickOutside } from './hooks/useClickOutside'

export const ExampleDebounce = () => {
  const [isOn, setOn] = React.useState(false)
  
  // Memoized callback for optimize
  const handleClickOutside = React.useCallback((event) => {
    event.preventDefault()
    event.stopPropagation()
    setOn(false)
  }, [isOn])

  const ref = useClickOutside(handleClickOutside)

  return (
    <div>
      <button onClick={() => setOn(true)}>Click me to show content</button>
      {isOn && <div ref={ref}>Click anywhere outside to hide me</div>}
    </div>
  )
}
2018 © Thành
RSS