-2

I referred to this Detect the Internet connection is offline? question to find out how to check if the browser is offline or online. So I used window.navigator.onLine to find that out.

The problem is that, no matter what I do, window.navigator.onLine is always true.

I am using brave browser, but I'm not sure if that's related to the issue, it's chromium based.

I'm on Ubuntu Linux, desktop.

I just want to detect when the browser becomes offline to show a small message "connection lost".

In react the code looks as follows:

const online = window.navigator.onLine
  useEffect(() => {
    if (online) return
    console.log("Connection lost!")
  }, [online])

try to toggle your wifi on and on to see the console logs

Here's a stack blitz instance to try it out, it's a pretty small code, (Click me)

Normal
  • 1,616
  • 15
  • 39
  • Need to use the event listener for this: window.addEventListener('online', () => { ...});. Inside the callback setstate to check online off-line toggle – Murtaza Hussain Jan 02 '23 at 13:06
  • Well that code won't run when you toggle your wifi, react has no reason to re-render the component? – Bergi Jan 02 '23 at 13:07
  • Yes, in browser it's always true –  Jan 02 '23 at 13:07
  • @Bergi, it will render a [snack bar](https://mui.com/material-ui/react-snackbar/), but this is just a demo, to console.log instead of rendering something – Normal Jan 02 '23 at 13:08
  • Check out here https://www.positronx.io/react-function-component-detect-internet-network-status-tutorial/ – Azhar Uddin Sheikh Jan 02 '23 at 14:05

2 Answers2

1

The property sends updates whenever the browser's ability to connect to the network changes. The update occurs when the user follows links or when a script requests a remote page.

https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine

So the value won't update unless you make a request of some sort.

There are also some implementation specific notes on the same url.

In Chrome and Safari, if the browser is not able to connect to a local area network (LAN) or a router, it is offline; all other conditions return true.

In other words, if there is any sort of network access it will be true, even if you are not connected to the internet.

So the best way to check this is probably to just make a request to an API endpoint or other resource that is only available while online and base your status on if the request was successful or not. Since in most cases just being "online" isn't worth much if your API is inaccessible this would probably provide better information to your users as well.

Karl-Johan Sjögren
  • 16,544
  • 7
  • 59
  • 68
  • Thanks. So there's no way to "watch" for such an event (regardless of being able to access the internet), – Normal Jan 02 '23 at 13:11
  • There is an event for this as Murtaza Hussain noted in the other answer. It still won't fire until there there is a request of some sort happening though and still has the same specifics for Chrome and Safari. – Karl-Johan Sjögren Jan 02 '23 at 13:18
1

Need to use the event listener for this: window.addEventListener('online', () => { ...});.

Inside the callback for listener, do setState to check online off-line toggle.

here is small hook i created in reactjs to handle online offline states:


import { useEffect, useState } from 'react';
// toastr alert messages 
import { showOffline, showOnline } from 'utils/alerts';

const useNetworkStatus = () => {
  const [state, setState] = useState(true);

  async function isOnline() {
    // if its offline and to check if window?.navigator is supported.
    if (!window?.navigator?.onLine) {
      setState(false);
      return false;
    }

    // Failover case:
    // navigator.onLine cannot be trusted: there's situation where you appear to be online (connect to a network with no internet)
    // but still cannot access the internet.
    // So to fix: we request to our own origin to avoid CORS errors
    const url = new URL(window.location.origin);
    //  with random value to prevent cached responses
    url.searchParams.set('rand', Date.now());

    try {
      const response = await fetch(url.toString(), { method: 'HEAD' });
      setState(true);
      return response.ok;
    } catch {
      setState(false);
      return false;
    }
  }

  useEffect(() => {
    const setOnlineOnVisibleChange = async () => {
      // if its page is visible and state was offline
      if (!document?.hidden && !state) {
        if (await isOnline()) showOnline();
      }
    };
    // on visiting the page again if the state is offline and network is online, then show online alert
    if ('hidden' in document)
      document.addEventListener('visibilitychange', setOnlineOnVisibleChange, false);
    return () => document.removeEventListener('visibilitychange', setOnlineOnVisibleChange, false);
  }, [state]);

  useEffect(() => {
    async function changeStatus() {
      if (await isOnline()) showOnline();
      else showOffline();
    }

    // Listen for the page to be finished loading
    window.addEventListener('load', () => {
      // if its offline
      if (!isOnline()) showOffline();
    });

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

export default useNetworkStatus;

Murtaza Hussain
  • 3,851
  • 24
  • 30
  • a great way to improve this hook is to seperate the hook logic from the UI, we can make it return an object like this: `const {isOnline, isOffline} = useConnectionChecker()`, then we can render any custom thing based on the isOnline or the isOffline properties – Normal Jan 02 '23 at 13:19
  • That sounds good, I'll modify the code, so that addresses the separation of concern – Murtaza Hussain Jan 02 '23 at 13:31