Динамическое изменение состояния на основе внешнего подключения к Интернету - React (автономно / онлайн)

9

У меня есть компонент React, который включает флаг доступности подключения к Интернету. Элементы пользовательского интерфейса должны динамически изменяться в соответствии с состоянием в реальном времени. Кроме того, функции ведут себя по-разному с изменениями флага.

Моя текущая реализация опрашивает удаленный API, используя Axios каждую секунду, используя интервал, и обновляет состояние соответственно. Я ищу более детальный и эффективный способ выполнить эту задачу, чтобы устранить 1-секундную ошибку состояния с минимальными вычислительными затратами. Рассматривается в режиме онлайн только в том случае, если устройство имеет внешнее подключение к Интернету.

Текущая реализация:

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

Отредактировано:

Ищете решение, способное обнаруживать внешние подключения к Интернету. Устройство может подключаться к локальной сети, которая не имеет внешнего подключения. Таким образом, это считается в автономном режиме. Рассматривает онлайн, если и только если устройство имеет доступ к внешним интернет-ресурсам.

Ниланка Маной
источник
2
Вам нужно знать, находитесь ли вы в автономном режиме или онлайн? или какое подключение к интернету?
tudor.gergely
Да. В основном онлайн или офлайн.
Ниланка Маной
Не могли бы вы изменить API, чтобы он открывал соединение через веб-сокет?
yadejo

Ответы:

2

Способ первый: использование устаревшего API браузера - Navigator.onLine

Возвращает онлайн-статус браузера. Свойство возвращает логическое значение с истинным значением онлайн и ложным значением автономно. Свойство отправляет обновления всякий раз, когда способность браузера подключаться к сети изменяется. Обновление происходит, когда пользователь переходит по ссылкам или когда скрипт запрашивает удаленную страницу. Например, свойство должно возвращать значение false, когда пользователи нажимают на ссылки вскоре после того, как теряют подключение к Интернету.

Вы можете добавить его в жизненный цикл вашего компонента:

Поиграйте с кодом ниже с помощью инструментов разработчика Chrome - переключите «Онлайн» на «Автономный» на вкладке «Сеть».

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>


Тем не менее, я думаю, что это не то, что вам нужно, вам нужен валидатор соединений в реальном времени .

Способ второй: проверка интернет-соединения с помощью него

Единственное надежное подтверждение, которое вы можете получить, если внешнее подключение к Интернету работает, - это использовать его. Вопрос в том, какой сервер вы должны назвать, чтобы минимизировать стоимость?

Для этого в Интернете существует множество решений, и любая конечная точка, которая отвечает с быстрым статусом 204, является идеальной, например:

  • звонить на сервер Google (потому что он самый проверенный в бою (?))
  • вызов его кэшированной конечной точки сценария JQuery (поэтому, даже если сервер не работает, вы все равно сможете получить сценарий, пока у вас есть соединение)
  • попробуйте загрузить изображение со стабильного сервера (например, https://ssl.gstatic.com/gb/images/v1_76783e20.png + отметка времени даты для предотвращения кэширования)

IMO, если вы запускаете это приложение React на сервере, имеет смысл обратиться к вашему собственному серверу, вы можете вызвать запрос на загрузку вашего /favicon.icoдля проверки соединения.

Эта идея (вызова своего собственного сервера) реализована многие библиотеки, такие как Offline, is-reachableи широко используется в сообществе. Вы можете использовать их, если не хотите писать все самостоятельно. (Лично мне нравится пакет NPM is-reachableза простоту.)

Пример:

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

Изменить соединение с сервером тестирования

Я считаю, что то, что у вас есть, уже хорошо, просто убедитесь, что оно вызывает правильную конечную точку.


Подобные вопросы SO:

Джи Мок
источник
8

Вы можете использовать https://developer.mozilla.org/en-US/docs/Web/API/Window/offline_event

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

и https://developer.mozilla.org/en-US/docs/Web/API/Window/online_event для проверки, когда вы снова в сети

window.addEventListener('online', (event) => {
    console.log("You are now connected to the network.");
});
tudor.gergely
источник
Локальная сеть может быть внешне отключена в моей ситуации :(
Ниланка Маной
2

Настройте пользовательский крючок

Установите хук с онлайн, оффлайн событиями. затем обновите состояние и верните его. Таким образом, вы можете использовать его в любом месте вашего приложения с импортом. Убедитесь, что вы очистите с помощью функции возврата. Если вы этого не сделаете, вы будете добавлять все больше и больше слушателей событий каждый раз, когда компонент подключается с помощью хуков.

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
}

Чтобы использовать это, просто импортируйте вышеуказанный хук и назовите его так.

const isOnline = onlineHook(); // true if online, false if not
Джо Ллойд
источник
Локальная сеть может быть внешне отключена в моей ситуации :(
Ниланка Маной
3
Если вы используете сокетную службу, такую ​​как firebase, вы можете использовать встроенное событие, которое фиксирует подключение к Интернету.
Джо Ллойд
Можете ли вы предоставить базовый каркас кода для предлагаемого подхода.
Ниланка Маной
2

Вы можете создать компонент для совместного использования между всеми подкомпонентами

используемый:

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

}
Эддвин Пас
источник
Вы забыли удалить прослушиватель событий?
Гаутамитс