back

React hooks are beautiful

As we all know React Hooks become more and more popular as their usage is extremely simple and leads to great dev experience.
I wanted to share with you couple of ideas on what you can also do with hooks to practice or implement it in your project

Event listeners

In Function Components we got used to assign event listeners on useEffect hook, and most of the time these code samples are the same and boring. So why not excluding this logic to hook to keep the space and increase readability of your code.
Here is the sample I wrote to assign listeners on specific events and unassign it on `unmount' of component:
import { useEffect } from 'react'

type MappedEventsToHandlers = {
  [key in keyof WindowEventMap as string]: () => void
}

const useEventListeners = (mappedEventsToHandlers: MappedEventsToHandlers) => {
  useEffect(() => {
    Object.keys(mappedEventsToHandlers).forEach(event => {
      window.addEventListener(event, mappedEventsToHandlers[event])
    })

    return () => {
      Object.keys(mappedEventsToHandlers).forEach(event => {
        window.removeEventListener(event, mappedEventsToHandlers[event])
      })
    }
  })
}

export default useEventListeners
To use this hook we may simply provide an object which will map every event (key) to handler (value) like this:
useEventListeners({
  scroll: onScroll,
  resize: () => console.log('resized'),
})
I find it very useful for components using web API to assign handlers to certain events. The big advantage of this hook is that by defining the type of key in object, VSCode, for example, will provide you with all options of possible events :)

Debounce

Recently, I made use of debounce method in my project. Then I have found out that this is a candidate to reuse in other places of code, so I come up with the following hook:
type CallbackType<T> = (value: T) => void

const useDebounce = <T>(callback: CallbackType<T>, ms): CallbackType<T> => {
  const [timer, setTimer] = useState<NodeJS.Timeout>()

  return (value: T) => {
    if(timer) {
      clearTimeout(timer)
    }

    setTimer(setTimeout(() => callback(value), ms))
  }
}

export default useDebounce
To use this hook we can simply put callback and ms as parameters and get a debounced version of callback you have provided:
const logValue = useDebounce((value) => console.log(value), 1000)
...
<input onChange={(e) => logValue(e.target.value)} ...

Conclusion

Hope you will find these hooks useful or just find an inspiration to make your own. Have fun!