An Idiosyncratic Blog

♼ Writing re-usable logic with React Hooks

Published on
4 minutes read

React developers who have used functional components are usually familiar with useEffect() and useState(). These are Hooks, which let you use state and other React features without writing a class.

You can implement your custom Hook that can be reused in your application or by others. Let me show a sample code that can detect whether a device is online or offline.

A custom Hook is a JavaScript function whose name starts with use and that may call other Hooks.

import React, { useEffect } from 'react'

const App = () => {
  const [isOnline, setIsOnline] = React.useState()

  const offline = () => setIsOnline(false)
  const online = () => setIsOnline(true)

  useEffect(() => {
    window.addEventListener('offline', offline)
    window.addEventListener('online', online)

    return () => {
      window.removeEventListener('offline', offline)
      window.removeEventListener('online', online)
    }
  }, [])

  if (!isOnline) {
    return <div>Sorry, you are offline ...</div>
  }

  return <div>You are online!</div>
}

export default App

The useEffect() adds and removes listeners that check if the device is online or offline. Both listeners are set up only once on mount (empty array as the second argument) and cleaned up on unmount. Whenever one of the events is triggered (online/offline), it updates the state isOnline.

What if we want to reuse this logic in multiple components or applications? It's just simply a matter of extracting the core logic to another function. We prefix this function with use to let others know at a glance that the rules of Hooks apply to it.

import React, { useEffect } from 'react'

const useOnline = () => {
  const [isOnline, setIsOnline] = React.useState()

  const offline = () => setIsOnline(false)
  const online = () => setIsOnline(true)

  useEffect(() => {
    window.addEventListener('offline', offline)
    window.addEventListener('online', online)

    return () => {
      window.removeEventListener('offline', offline)
      window.removeEventListener('online', online)
    }
  }, [])

  return isOnline
}

There’s nothing new here — the logic is copied from the component above. Our goal was to be able to re-use the logic to check if device is online or offline, and now that we have extracted this logic to a useOnline hook, we can use it like:

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

const App = () => {
  const isOnline = useOnline()

  if (!isOnline) {
    return <div>Sorry, you are offline ...</div>
  }

  return <div>You are online!</div>
}

export default App

Is this code equivalent to the original examples? Yep, it works in exactly the same way, since we didn't make any changes to the behavior. All we did was to extract a core logic into a separate function.

Custom Hooks are a convention that naturally follows from the design of Hooks, rather than a React feature. - React Docs

That's it for the custom hook that detects whether you are online or offline. You can read more about custom hooks in React's documentation.

If you want to look at more complex usages of custom hooks, checkout useHooks(🐠) by ui.dev