Custom React Hooks: useNetworkState
Tags: react, javascript, programming, webdev
Published: 2021-11-28 16:05:34

In the last episode of the [Custom React Hooks](https://dev.to/iamludal/series/14964) series, we've implemented the [useLocalStorage](https://dev.to/iamludal/custom-react-hooks-uselocalstorage-309p) hook to simplify local storage management. In today's episode, we'll create a hook to simplify the observation of our users network state: `useNetworkState`.

- [Motivation](#motivation)
- [Implementation](#implementation)
- [Usage](#usage)
- [Conclusion](#conclusion)
- [Support Me](#support-me)

## Motivation

Let's say you're building an application that requires to be online in order to work correctly. If the user gets disconnected, you want to display a toast message informing it to check its network connectivity. To do this in a React app, here's how you could proceed:

```jsx
const App = () => {
  const [isOnline, setIsOnline] = useState(window.navigator.onLine);

  useEffect(() => {
    const handleOnline = () => {
      setIsOnline(true);
    };
    const handleOffline = () => {
      setIsOnline(false);
    };
    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);

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

  return (
    <div>
      <h1>My Awesome App</h1>
      <p>
        Lorem, ipsum dolor sit amet consectetur adipisicing elit. Culpa
        provident tenetur molestias fugiat expedita quaerat dolores dignissimos
        dicta, error amet reiciendis voluptates delectus perspiciatis dolorum
        saepe, sunt, similique vitae illo.
      </p>
      {!isOnline && (
        <div className="toast">
          You are offline. Please check your connectivity and try again.
        </div>
      )}
    </div>
  );
};
```

This works fine, but this is already a lot of code, and above all a lot of logic just inside the `useEffect` hook. Our goal is to define a `useNetworkState` hook that will abstract this logic inside a custom hook, that is reusable over the entire app to listen for network state changes. This will also reduce the code inside our `App` component, that could quickly get longer and longer if we add some other logic (click listeners, form submission, keyboard listeners...).

## Implementation

As always, let's think about the interface of our hook (how we are going to use it). In our case, we could have something as simple as this one-liner:

```jsx
const isOnline = useNetworkState()
```

Pretty straightforward. This hook would return a single boolean value that gets updated accordingly to synchronize with the network status.

We can already dive into the hook's implementation, by only extracting the logic we've written in the `useEffect` hook of our `App` component. At the end, the hook will look like this:

```jsx
const useNetworkState = () => {
  const [isOnline, setIsOnline] = useBoolean(window.navigator.onLine);

  useEffect(() => {
    window.addEventListener('online', setIsOnline.on);
    window.addEventListener('offline', setIsOnline.off);

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

  return isOnline;
};
```

Wait, what the heck is `useBoolean`? This hook doesn't exist... 🤨

Yes, you're right. However, if you've been following this series from the very first episode, this hook might remind you something... as it is the first custom hook we've implemented! If you've discovered this series on the way, no problem: just head over to [this link](https://dev.to/iamludal/react-custom-hooks-useboolean-3m6c), that will bring you to my article on the `useBoolean` hook.

> Note: if you don't want to use the `useBoolean` hook, you can be satisfied with the native `useState` one, and `useNetworkState` would be the following:
> 
> 
> ```jsx
> const useNetworkState = () => {
>   const [isOnline, setIsOnline] = useState(window.navigator.onLine);
> 
>   useEffect(() => {
>     const handleOnline = () => {
>       setIsOnline(true);
>     };
>     const handleOffline = () => {
>       setIsOnline(false);
>     };
>     window.addEventListener('online', handleOnline);
>     window.addEventListener('offline', handleOffline);
> 
>     return () => {
>       window.removeEventListener('online', handleOnline);
>       window.removeEventListener('offline', handleOffline);
>     };
>   }, []);
> 
>   return isOnline;
> };
> ```
> 

## Usage

Back to our `App` component, where we can drastically simplify the code (see by yourself):

```jsx
const App = () => {
  const isOnline = useNetworkState()

  return (
    <div>
      <h1>My Awesome App</h1>
      <p>
        Lorem, ipsum dolor sit amet consectetur adipisicing elit. Culpa
        provident tenetur molestias fugiat expedita quaerat dolores dignissimos
        dicta, error amet reiciendis voluptates delectus perspiciatis dolorum
        saepe, sunt, similique vitae illo.
      </p>
      {!isOnline && (
        <div className="toast">
          You are offline. Please check your connectivity and try again.
        </div>
      )}
    </div>
  );
};
```

Yes, yes. One-line. Awesome, right? 😎

All the logic is now abstracted outside of the component, that only focuses on what matters to it. By doing this, we're following the SOC (Separation of Concerns) design principle — more information [here](https://en.wikipedia.org/wiki/Separation_of_concerns).

## Conclusion

I hope this hook will be useful to you for your projects. If you have any questions, feel free to ask them in the comments section. For now, thanks for reading me, and see you next time for a new custom hook. 🤗

---

**Source code** available on [CodeSanbox](https://codesandbox.io/s/custom-react-hooks-usenetworkstate-354j0?file=/src/App.tsx).

{% codesandbox 354j0 %}

---

## Support Me

If you wish to support me, you can click the following link to buy me a coffee (which I will then probably turn into a new custom hook... ☕).

[![Buy Me A Coffee](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0dtg9yyg5inqtn4l67fb.png)](https://www.buymeacoffee.com/iamludal)