Dynamicznie zmieniaj stan w oparciu o zewnętrzną łączność z Internetem - React (offline / online)

10

Mam komponent React, który obejmuje flagę dostępności połączenia internetowego. Elementy interfejsu użytkownika należy dynamicznie zmieniać zgodnie ze stanem w czasie rzeczywistym. Ponadto funkcje zachowują się inaczej ze zmianami flagi.

Moja bieżąca implementacja odpytuje zdalny interfejs API przy użyciu Axios w każdej sekundzie, używając odpowiednio okresu i aktualizacji. Szukam bardziej szczegółowego i wydajnego sposobu wykonania tego zadania, aby usunąć 1-sekundowy błąd stanu przy minimalnych kosztach obliczeniowych. Rozważany online , tylko jeśli urządzenie ma zewnętrzne połączenie z Internetem

Obecna realizacja:

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

Edytowane:

Poszukuje rozwiązania zdolnego do wykrywania zewnętrznej łączności z Internetem. Urządzenie może połączyć się z siecią LAN, która nie ma połączenia zewnętrznego. Jest to uważane za offline. Rozważa online wtedy i tylko wtedy , gdy urządzenie ma dostęp do zewnętrznych zasobów internetowych.

Nilanka Manoj
źródło
2
czy chcesz wiedzieć, czy jesteś offline, czy online? lub jaką łączność z Internetem?
tudor.gergely
Tak. Zasadniczo online lub offline.
Nilanka Manoj
czy możesz zmienić interfejs API, aby ujawniał połączenie z gniazdem sieciowym?
yadejo

Odpowiedzi:

2

Metoda 1: Korzystanie ze starszego interfejsu API przeglądarki - Navigator.onLine

Zwraca status online przeglądarki. Właściwość zwraca wartość logiczną o prawdziwym znaczeniu online i fałszywym znaczeniu offline. Właściwość wysyła aktualizacje za każdym razem, gdy zdolność przeglądarki do łączenia się z siecią zmienia się. Aktualizacja następuje, gdy użytkownik korzysta z łączy lub gdy skrypt żąda strony zdalnej. Na przykład właściwość powinna zwrócić wartość false, gdy użytkownicy klikną łącza wkrótce po utracie połączenia z Internetem.

Możesz dodać go do swojego cyklu życia komponentu:

Graj za pomocą poniższego kodu za pomocą narzędzi programistycznych Chrome - przełącz „Online” na „Offline” na karcie Sieć.

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>


Myślę jednak, że to nie jest to, czego chciałeś, chciałeś walidatora połączenia w czasie rzeczywistym .

Metoda druga: Sprawdzanie połączenia internetowego za pomocą go

Jedynym solidnym potwierdzeniem, które można uzyskać, jeśli działa zewnętrzne połączenie internetowe, jest jego użycie. Pytanie brzmi, do którego serwera należy zadzwonić, aby zminimalizować koszty?

Istnieje wiele rozwiązań w Internecie, każdy punkt końcowy, który odpowiada szybkim statusem 204, jest idealny, np .:

  • dzwonienie do serwera Google (ponieważ jest to najbardziej przetestowany w bitwie (?))
  • wywołując buforowany punkt końcowy skryptu JQuery (więc nawet jeśli serwer jest wyłączony, nadal powinieneś być w stanie uzyskać skrypt, dopóki masz połączenie)
  • spróbuj pobrać obraz ze stabilnego serwera (np .: https://ssl.gstatic.com/gb/images/v1_76783e20.png + datownik, aby zapobiec buforowaniu)

IMO, jeśli używasz tej aplikacji React na serwerze, najlepiej jest zadzwonić na własny serwer, możesz zadzwonić z prośbą o załadowanie, /favicon.icoaby sprawdzić połączenie.

Ten pomysł (nazywając swój własny serwer) został wdrożony w wielu bibliotekach, takich jak Offline, is-reachablei jest powszechnie stosowany w całej Wspólnocie. Możesz ich użyć, jeśli nie chcesz wszystkiego pisać samodzielnie. (Osobiście podoba mi się pakiet NPM is-reachableza prostotę.)

Przykład:

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

Edytuj połączenie z serwerem testowym

Uważam, że to, co obecnie masz, jest już w porządku, po prostu upewnij się, że wywołuje właściwy punkt końcowy.


Podobne pytania SO:

Jee Mok
źródło
8

Możesz użyć https://developer.mozilla.org/en-US/docs/Web/API/Window/offline_event

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

i https://developer.mozilla.org/en-US/docs/Web/API/Window/online_event do sprawdzania, kiedy jesteś ponownie online

window.addEventListener('online', (event) => {
    console.log("You are now connected to the network.");
});
tudor.gergely
źródło
LAN może być odłączony zewnętrznie w mojej sytuacji :(
Nilanka Manoj
2

Skonfiguruj niestandardowy hak

Przygotuj hak z wydarzeniami online, offline. następnie zaktualizuj stan i zwróć go. W ten sposób możesz go używać w dowolnym miejscu w aplikacji dzięki importowi. Upewnij się, że posprzątasz z funkcją powrotu. Jeśli tego nie zrobisz, będziesz dodawał coraz więcej detektorów zdarzeń za każdym razem, gdy komponent korzystający z zaczepów zostanie podłączony.

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
}

Aby tego użyć, wystarczy zaimportować powyższy hak i nazwać go w ten sposób.

const isOnline = onlineHook(); // true if online, false if not
Joe Lloyd
źródło
LAN może być odłączony zewnętrznie w mojej sytuacji :(
Nilanka Manoj
3
Jeśli korzystasz z usługi gniazdowej, takiej jak firebase, możesz użyć wbudowanego zdarzenia, które przechwytuje łączność z Internetem.
Joe Lloyd
czy możesz podać podstawowy szkielet kodu dla sugerowanego podejścia?
Nilanka Manoj
2

Możesz utworzyć komponent, który będzie współużytkowany przez wszystkie podskładniki

używany:

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
źródło
Zapomniałeś usunąć detektora zdarzeń?
gautamits