Alterar estado dinamicamente com base na conectividade externa à Internet - Reagir (offline / online)

9

Eu tenho um componente React, que inclui o sinalizador de disponibilidade da conectividade com a Internet. Os elementos da interface do usuário precisam ser alterados dinamicamente de acordo com o estado em tempo real. Além disso, as funções se comportam de maneira diferente com a alteração do sinalizador.

Minha implementação atual pesquisa a API remota usando o Axios a cada segundo, usando o intervalo e o estado das atualizações de acordo. Estou procurando uma maneira mais granular e eficiente de executar esta tarefa para remover o erro de estado de 1 segundo com o custo computacional mínimo. Considerado online se e somente se o dispositivo tiver uma conexão externa à Internet

Implementação atual:

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:

Procurando uma solução capaz de detectar conectividade externa à Internet. O dispositivo pode se conectar a uma LAN que não possui uma conexão externa. Portanto, é considerado offline. Considera on-line se e somente se o dispositivo tiver acesso a recursos externos da Internet.

Nilanka Manoj
fonte
2
você precisa saber se está offline ou online? ou qual conectividade com a internet?
tudor.gergely 31/03
Sim. Basicamente online ou offline.
Nilanka Manoj 31/03
você pode alterar a API para expor uma conexão de websocket?
yadejo 22/04

Respostas:

2

Método 1: Usando a API do navegador herdado - Navigator.onLine

Retorna o status online do navegador. A propriedade retorna um valor booleano, com verdadeiro significado online e falso significado offline. A propriedade envia atualizações sempre que a capacidade do navegador de se conectar à rede mudar. A atualização ocorre quando o usuário segue os links ou quando um script solicita uma página remota. Por exemplo, a propriedade deve retornar false quando os usuários clicarem em links logo após perderem a conexão com a Internet.

Você pode adicioná-lo ao seu ciclo de vida do componente:

Jogue com o código abaixo usando as ferramentas de desenvolvimento do Chrome - alterne "Online" para "Off-line" na guia Rede.

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>


No entanto, acho que não é isso que você deseja, você queria um validador de conexão em tempo real .

Método 2: Verificando a conexão à Internet usando-o

A única confirmação sólida que você pode obter se a conectividade externa à Internet estiver funcionando é usando-a. A questão é: qual servidor você deve ligar para minimizar o custo?

Existem muitas soluções na Internet para isso, qualquer ponto de extremidade que responda com um status 204 rápido é perfeito, por exemplo:

  • ligando para o servidor do Google (por ser o mais testado em batalha (?))
  • chamando seu terminal de script JQuery em cache (portanto, mesmo se o servidor estiver inativo, você ainda poderá obter o script enquanto tiver uma conexão)
  • tente buscar uma imagem de um servidor estável (por exemplo: https://ssl.gstatic.com/gb/images/v1_76783e20.png + data e hora para impedir o armazenamento em cache)

IMO, se você estiver executando este aplicativo React em um servidor, faz mais sentido ligar para o seu próprio servidor, você pode chamar uma solicitação para carregar o seu /favicon.icopara verificar a conexão.

Essa idéia (de chamar o seu próprio servidor) foi implementada por muitas bibliotecas, como Offline, is-reachable, e é amplamente utilizado em toda a comunidade. Você pode usá-los se não quiser escrever tudo sozinho. (Pessoalmente, gosto do pacote NPM is-reachablepor ser simples.)

Exemplo:

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 conexão do servidor de teste

Acredito que o que você tem atualmente já está bom, apenas verifique se ele está chamando o endpoint correto.


Perguntas SO semelhantes:

Jee Mok
fonte
8

Você pode 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.");
});

e https://developer.mozilla.org/en-US/docs/Web/API/Window/online_event para verificar quando você está online novamente

window.addEventListener('online', (event) => {
    console.log("You are now connected to the network.");
});
tudor.gergely
fonte
A LAN pode ser desconectada externamente na minha situação :(
Nilanka Manoj em 31/03
2

Configurar um gancho personalizado

Configure um gancho com os eventos online e offline. atualize um estado e retorne-o. Dessa forma, você pode usá-lo em qualquer lugar do seu aplicativo com uma importação. Certifique-se de limpar com a função de retorno. Caso contrário, você adicionará cada vez mais ouvintes de eventos sempre que um componente usando o gancho for montado.

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 isso, importe o gancho acima e chame-o assim.

const isOnline = onlineHook(); // true if online, false if not
Joe Lloyd
fonte
A LAN pode ser desconectada externamente na minha situação :(
Nilanka Manoj em 31/03
3
Se você usar um serviço em soquete como o firebase, poderá usar um evento interno que captura a conectividade com a Internet.
Joe Lloyd
você pode fornecer um esqueleto básico de código para a abordagem sugerida.
Nilanka Manoj
2

Você pode criar um componente para compartilhar entre todos os subcomponentes

usava:

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
fonte
Você esqueceu de remover o ouvinte de evento?
gautamits 24/04