简体   繁体   English

根据外部 Internet 连接动态更改状态 - React(离线/在线)

[英]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.我有一个 React 组件,其中包括 Internet 连接的可用性标志。 UI elements have to be dynamically changed according to state real-time. UI 元素必须根据状态实时动态更改。 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.我当前的实现使用间隔每秒使用 Axios 轮询远程 API,并相应地更新状态。 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.我正在寻找一种更精细、更有效的方法来完成这项任务,以最小的计算成本消除 1 秒的状态错误。 Considered online if and only if device has an external Internet connection当且仅当设备具有外部 Internet 连接时才考虑在线

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.寻找能够检测外部 Internet 连接的解决方案。 The device can connect to a LAN which doesn't have an external connection.设备可以连接到没有外部连接的 LAN。 So, it is considered offline.所以,它被认为是离线的。 Considers online if and only if device has access to external Internet resources.当且仅当设备可以访问外部 Internet 资源时才考虑在线。

You can use https://developer.mozilla.org/en-US/docs/Web/API/Window/offline_event您可以使用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 onlinehttps://developer.mozilla.org/en-US/docs/Web/API/Window/online_event用于检查您何时重新上线

window.addEventListener('online', (event) => {
    console.log("You are now connected to the network.");
});

Method one: Using legacy browser API - Navigator.onLine方法一:使用旧版浏览器 API - Navigator.onLine

Returns the online status of the browser.返回浏览器的在线状态。 The property returns a boolean value, with true meaning online and false meaning offline.该属性返回一个布尔值,true 表示在线,false 表示离线。 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.例如,当用户在失去 Internet 连接后不久单击链接时,该属性应返回 false。

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.使用 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>


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, eg:互联网上有很多解决方案,任何以快速 204 状态响应的端点都是完美的,例如:

  • 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)调用其缓存的 JQuery 脚本端点(因此即使服务器关闭,只要有连接,您仍然应该能够获取脚本)
  • try fetching an image from a stable server (eg: https://ssl.gstatic.com/gb/images/v1_76783e20.png + date timestamp to prevent caching)尝试从稳定的服务器获取图像(例如: https : //ssl.gstatic.com/gb/images/v1_76783e20.png + 日期时间戳以防止缓存)

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. IMO,如果你在服务器上运行这个 React 应用程序,调用你自己的服务器是最有意义的,你可以调用一个请求来加载你的/favicon.ico来检查连接。

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.这个想法(调用你自己的服务器)已经被许多库实现,比如Offlineis-reachable ,并且在社区中被广泛使用。 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.) (我个人喜欢 NPM 包is-reachable因为它很简单。)

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

编辑测试服务器连接

I believe what you have currently is already fine, just make sure that it is calling the right endpoint.我相信您目前所拥有的已经很好,只需确保它正在调用正确的端点。


Similar SO questions:类似的问题:

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

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

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM