Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change state dynamically based on the external Internet connectivity - React (offline/online)

I have a React component, that includes the availability flag of Internet connectivity. UI elements have to be dynamically changed according to state real-time. Also, functions behave differently with the changes of the flag.

My current implementation polls remote API using Axios in every second using interval and updates state accordingly. I am looking for a more granular and efficient way to do this task to remove the 1-second error of state with the minimum computational cost. Considered online if and only if device has an external Internet connection

Current implementation :

class Container extends Component {
  constructor(props) {
    super(props)
    this.state = {
      isOnline: false
    };
    this.webAPI = new WebAPI(); //Axios wrapper
  }

  componentDidMount() {
    setInterval(() => {
      this.webAPI.poll(success => this.setState({ isOnline: success });
    }, 1000);
  }

  render() {
    return <ChildComponent isOnline={this.state.isOnline} />;
  }
}

Edited:

Looking for a solution capable of detecting external Internet connectivity. The device can connect to a LAN which doesn't have an external connection. So, it is considered offline. Considers online if and only if device has access to external Internet resources.

like image 280
Nilanka Manoj Avatar asked Mar 31 '20 07:03

Nilanka Manoj


People also ask

Which method is used to change the state data in React?

setState() setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. This is the primary method you use to update the user interface in response to event handlers and server responses.

Can we change state of one component from another React?

There are basically two ways to share state between multiple components: Shift state into a parent component. Store the state externally using React Context or a state framework like Redux.

Can I run React without internet?

Offline-first means that you build your React Native app so that it can work with or without an Internet connection.

What is react-detect-offline and how do I use it?

The “react-detect-offline” package can also be used to display content or style your content based on your network connectivity (connected/disconnected). If an app is likely to be used in poor network areas or while travelling then it’s probably best to go with an “ Offline first ” approach.

What is offline first app in react?

An offline first app is an app whose core functionality works even in the absence of a network connection. When we create a react app using create-react-app command (assuming we have all the requirements to run react app on our system), the app will contain a file called “service-worker.js” .

How do I update the isdisconnected property in the local state?

In the component above, we have the handleConnectionChange method that updates the isDisconnected property in our local state as a result of a change in the Javascript “navigator.onLine” property which returns a boolean. This boolean is changed and updated accordingly based on the browser’s ability to fetch any resource on the internet.


4 Answers

You can use https://developer.mozilla.org/en-US/docs/Web/API/Window/offline_event

window.addEventListener('offline', (event) => {
    console.log("The network connection has been lost.");
});

and https://developer.mozilla.org/en-US/docs/Web/API/Window/online_event for checking when you're back online

window.addEventListener('online', (event) => {
    console.log("You are now connected to the network.");
});
like image 151
tudor.gergely Avatar answered Oct 23 '22 07:10

tudor.gergely


Method one: Using legacy browser API - Navigator.onLine

Returns the online status of the browser. The property returns a boolean value, with true meaning online and false meaning offline. 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. For example, the property should return false when users click links soon after they lose internet connection.

You can add it to your component lifecycle:

Play with the code below using Chrome dev tools - switch "Online" to "Offline" under the Network tab.

class App extends React.PureComponent {
  state = { online: window.navigator.onLine }
  
  componentDidMount() {
    window.addEventListener('offline', this.handleNetworkChange);
    window.addEventListener('online', this.handleNetworkChange);
  }
  
  componentWillUnmount() {
    window.removeEventListener('offline', this.handleNetworkChange);
    window.removeEventListener('online', this.handleNetworkChange);
  }
  
  handleNetworkChange = () => {
    this.setState({ online: window.navigator.onLine });
  }
  
  render() {
    return (
      <div>
       { this.state.online ? 'you\'re online' : 'you\'re offline' }
      </div>
    );
  }
}

ReactDOM.render(
  <App />
, document.querySelector('#app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

However, I think this isn't what you want, you wanted a real-time connection validator.

Method two: Checking internet connection by using it

The only solid confirmation you can get if the external internet connectivity is working is by using it. The question is which server you should call to minimize the cost?

There are many solutions on the internet for this, any endpoint that responds with a quick 204 status is perfect, e.g.:

  • calling to Google server (for it being the most battle-tested (?) )
  • calling its cached JQuery script endpoint (so even if the server is down, you should still be able to get the script as long as you have a connection)
  • try fetching an image from a stable server (e.g.: https://ssl.gstatic.com/gb/images/v1_76783e20.png + date timestamp to prevent caching)

IMO, if you are running this React app on a server, it makes the most sense to call to your own server, you can call a request to load your /favicon.ico to check the connection.

This idea (of calling your own server) has been implemented by many libraries, such as Offline, is-reachable, and is widely used across the community. You can use them if you don't want to write everything by yourself. (Personally I like the NPM package is-reachable for being simple.)

Example:

import React from 'react';
import isReachable from 'is-reachable';

const URL = 'google.com:443';
const EVERY_SECOND = 1000;

export default class App extends React.PureComponent {
  _isMounted = true;

  state = { online: false }

  componentDidMount() {
    setInterval(async () => {
      const online = await isReachable(URL);

      if (this._isMounted) {
        this.setState({ online });
      }
    }, EVERY_SECOND);
  }

  componentWillUnmount() {
    this._isMounted = false;
  }

  render() {
    return (
      <div>
       { this.state.online ? 'you\'re online' : 'you\'re offline' }
      </div>
    );
  }
}

Edit Testing Server Connection

I believe what you have currently is already fine, just make sure that it is calling the right endpoint.


Similar SO questions:

  • Detect the Internet connection is offline?
  • Detect network connection in React Redux app - if offline, hide component from user
  • https://stackoverflow.com/Questions/3181080/How-To-Detect-Online-Offline-Event-Cross-Browser
like image 31
Jee Mok Avatar answered Oct 23 '22 09:10

Jee Mok


Setup a custom hook

Setup a hook with the online, offline events. then update a state and return it. This way you can use it anywhere in your app with an import. Make sure you clean up with the return function. If you don't you will add more and more event listeners each time a component using the hook mounts.

const onlineHook = () => {
  const {isOnline, setOnline} = React.useState();

  React.useEffect(() => {
    const goOnline = function(event){
      setOnline(true);
    });
    const goOffline = function(event){
      setOnline(false);
    });

    window.addEventListener('offline', goOffline);
    window.addEventListener('online', goOnline);

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

  return isOnline
}

To use this just import the above hook and call it like this.

const isOnline = onlineHook(); // true if online, false if not
like image 1
Joe Lloyd Avatar answered Oct 23 '22 09:10

Joe Lloyd


You can create a component to share between all subcomponents

used:

import React, { useState, useEffect } from "react";

export default function NetworkChecker() {

  const [networkStatus, setNetworkStatus] = useState(true)

  useEffect(() => {
    window.addEventListener('offline', (event) => {
      setNetworkStatus(false)
    });

    window.addEventListener('online', (event) => {
      setNetworkStatus(true)
    });

    return function cleanupListener() {
       window.removeEventListener('online',  setNetworkStatus(true))
       window.removeEventListener('offline', setNetworkStatus(false))
     }

  },[])

  if (networkStatus) {
    return <div className={"alert-success"}>Online</div>
  } else {
    return <div className={"alert-danger"}>Offline</div>
  }

}
like image 1
Eddwin Paz Avatar answered Oct 23 '22 07:10

Eddwin Paz