Cambiar el estado dinámicamente en función de la conectividad a Internet externa - Reaccionar (fuera de línea / en línea)

9

Tengo un componente React, que incluye el indicador de disponibilidad de la conectividad a Internet. Los elementos de la interfaz de usuario deben cambiarse dinámicamente según el estado en tiempo real. Además, las funciones se comportan de manera diferente con el cambio de bandera.

Mi implementación actual sondea API remota usando Axios en cada segundo usando intervalos y actualiza el estado en consecuencia. Estoy buscando una forma más granular y eficiente de hacer esta tarea para eliminar el error de estado de 1 segundo con el mínimo costo computacional. Considerado en línea si y solo si el dispositivo tiene una conexión a Internet externa

Implementación actual:

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} />;
  }
}

Editado:

Buscando una solución capaz de detectar conectividad externa a Internet. El dispositivo puede conectarse a una LAN que no tiene una conexión externa. Por lo tanto, se considera fuera de línea. Considera en línea si y solo si el dispositivo tiene acceso a recursos externos de Internet.

Nilanka Manoj
fuente
2
¿necesita saber si está desconectado o en línea? o qué conectividad a internet?
tudor.gergely
Si. Básicamente en línea o fuera de línea.
Nilanka Manoj
¿podría alterar la API para que exponga una conexión websocket?
yadejo

Respuestas:

2

Método uno: Uso de la API de navegador heredada - Navigator.onLine

Devuelve el estado en línea del navegador. La propiedad devuelve un valor booleano, con verdadero significado en línea y falso significado sin conexión. La propiedad envía actualizaciones cada vez que cambia la capacidad del navegador para conectarse a la red. La actualización se produce cuando el usuario sigue enlaces o cuando un script solicita una página remota. Por ejemplo, la propiedad debería devolver false cuando los usuarios hacen clic en los enlaces poco después de perder la conexión a Internet.

Puede agregarlo al ciclo de vida de su componente:

Juega con el siguiente código utilizando las herramientas de desarrollo de Chrome: cambia "En línea" a "Fuera de línea" en la pestaña Red.

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>


Sin embargo, creo que esto no es lo que quieres, querías un validador de conexión en tiempo real .

Método dos: verificar la conexión a Internet usándolo

La única confirmación sólida que puede obtener si la conectividad a Internet externa funciona es usándola. La pregunta es a qué servidor debe llamar para minimizar el costo.

Hay muchas soluciones en Internet para esto, cualquier punto final que responda con un estado 204 rápido es perfecto, por ejemplo:

  • llamando al servidor de Google (por ser el más probado en batalla (?))
  • llamando a su punto final de script JQuery en caché (por lo que incluso si el servidor está inactivo, aún debería poder obtener el script siempre que tenga una conexión)
  • intente buscar una imagen de un servidor estable (por ejemplo: https://ssl.gstatic.com/gb/images/v1_76783e20.png + fecha y hora para evitar el almacenamiento en caché)

OMI, si está ejecutando esta aplicación React en un servidor, tiene más sentido llamar a su propio servidor, puede llamar a una solicitud para cargar su /favicon.icopara verificar la conexión.

Esta idea (de llamar a su propio servidor) ha sido implementado por muchas bibliotecas, tales como Offline, is-reachabley es ampliamente utilizado en toda la comunidad. Puedes usarlos si no quieres escribir todo por ti mismo. (Personalmente, me gusta el paquete NPM is-reachablepor ser simple).

Ejemplo:

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>
    );
  }
}

Editar conexión del servidor de prueba

Creo que lo que tiene actualmente ya está bien, solo asegúrese de que esté llamando al punto final correcto.


Preguntas SO similares:

Jee Mok
fuente
8

Puede usar https://developer.mozilla.org/en-US/docs/Web/API/Window/offline_event

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

y https://developer.mozilla.org/en-US/docs/Web/API/Window/online_event para verificar cuándo vuelve a estar en línea

window.addEventListener('online', (event) => {
    console.log("You are now connected to the network.");
});
tudor.gergely
fuente
LAN se puede desconectar externamente en mi situación :(
Nilanka Manoj
2

Configurar un gancho personalizado

Configure un enlace con los eventos en línea y fuera de línea. luego actualice un estado y devuélvalo. De esta manera, puede usarlo en cualquier lugar de su aplicación con una importación. Asegúrese de limpiar con la función de retorno. Si no lo hace, agregará más y más oyentes de eventos cada vez que un componente use los montajes de gancho.

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
}

Para usar esto solo importa el gancho anterior y llámalo así.

const isOnline = onlineHook(); // true if online, false if not
Joe Lloyd
fuente
LAN se puede desconectar externamente en mi situación :(
Nilanka Manoj
3
Si usa un servicio enchufable como firebase, puede usar un evento incorporado que capture la conectividad a Internet.
Joe Lloyd
¿Puede proporcionar un esqueleto básico de código para el enfoque sugerido?
Nilanka Manoj
2

Puede crear un componente para compartir entre todos los subcomponentes.

usado:

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>
  }

}
Eddwin Paz
fuente
¿Olvidaste eliminar el detector de eventos?
Gautamits