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

Posted

技术标签:

【中文标题】根据外部 Internet 连接动态更改状态 - React(离线/在线)【英文标题】:Change state dynamically based on the external Internet connectivity - React (offline/online) 【发布时间】:2020-07-11 16:19:52 【问题描述】:

我有一个 React 组件,其中包括 Internet 连接的可用性标志。 UI 元素必须根据状态实时动态改变。此外,随着标志的变化,函数的行为也会有所不同。

我当前的实现使用 Axios 每隔一秒使用间隔轮询远程 API,并相应地更新状态。我正在寻找一种更精细、更有效的方法来完成这项任务,以最小的计算成本消除 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 />;
  

已编辑:

正在寻找能够检测外部 Internet 连接的解决方案。该设备可以连接到没有外部连接的 LAN。所以,它被认为是离线的。 当且仅当设备可以访问外部互联网资源时才考虑在线。

【问题讨论】:

您需要知道您是离线还是在线?或什么互联网连接? 是的。基本上在线或离线。 你能改变 API 让它暴露一个 websocket 连接吗? 【参考方案1】:

您可以使用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.");
);

【讨论】:

在我的情况下局域网可以外部断开:(【参考方案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

【讨论】:

在我的情况下局域网可以外部断开:( 如果您使用像 firebase 这样的套接字服务,您可以使用捕获互联网连接的内置事件。 您能否提供建议方法的基本代码框架。【参考方案3】:

您可以创建一个组件在所有子组件之间共享

使用:

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>
  


【讨论】:

你忘了移除事件监听器?【参考方案4】:

方法一:使用旧版浏览器 API - Navigator.onLine

返回浏览器的在线状态。该属性返回一个布尔值,true 表示在线,false 表示离线。每当浏览器连接到网络的能力发生变化时,该属性都会发送更新。当用户点击链接或脚本请求远程页面时,会发生更新。例如,当用户在失去互联网连接后不久单击链接时,该属性应返回 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 来检查连接。

这个想法(调用你自己的服务器)已经被许多库实现了,例如Offlineis-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 问题:

Detect the Internet connection is offline? Detect network connection in React Redux app - if offline, hide component from user https://***.com/Questions/3181080/How-To-Detect-Online-Offline-Event-Cross-Browser

【讨论】:

以上是关于根据外部 Internet 连接动态更改状态 - React(离线/在线)的主要内容,如果未能解决你的问题,请参考以下文章

安卓的权限大全和动态使用安卓权限

路由器动态和静态IP怎么设置?

Android的BroadcastReceiver组件

如何根据前景图像在android中动态更改状态栏的颜色?

怎样连接共享文件夹

根据状态动态更改登录/注销按钮