最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to monitor network status change in react components - Stack Overflow

programmeradmin0浏览0评论

There are two event listeners that are apparently useful when to monitor the network status:

1. window.addEventListener('online', console.log('Online'));
2. window.addEventListener('offline', console.log('Offline'));

But I am not sure where to register and use them. When I use them within ponentDidMount, there is no use because monitoring would happen only if the ponent is mounted. I want to monitor the network status in one place and use it across the application. For this, dispatching the network status in redux would be more helpful. But the problem is where to listen for this events.

There are two event listeners that are apparently useful when to monitor the network status:

1. window.addEventListener('online', console.log('Online'));
2. window.addEventListener('offline', console.log('Offline'));

But I am not sure where to register and use them. When I use them within ponentDidMount, there is no use because monitoring would happen only if the ponent is mounted. I want to monitor the network status in one place and use it across the application. For this, dispatching the network status in redux would be more helpful. But the problem is where to listen for this events.

Share Improve this question asked Nov 25, 2019 at 14:15 PremPrem 6,01716 gold badges61 silver badges101 bronze badges 4
  • 1 How about setting the listener in App.js ponentDidMount()? On it's callback you can call a redux action to store the data in any way you like. Don't forget to store the reference in order to clear it on unMount. – Sagi Rika Commented Nov 25, 2019 at 14:18
  • This answer is going to be big. Basically have the root container start listening when it mounts, And dispatch actions to your redux store to indicate when network status changes. What parts of this will you need explained? – Wyck Commented Nov 25, 2019 at 14:18
  • @Wyck For example, if the network connectivity is lost when i'm using the application, can I detect it?. In this scenario, ponentDidMount is not triggered for root container. – Prem Commented Nov 25, 2019 at 14:31
  • Would react-detect-offline solve your problem? – Tomasz Kasperczyk Commented Nov 25, 2019 at 14:54
Add a ment  | 

5 Answers 5

Reset to default 2

Simplified example with class ponents:

// In your main App ponent
ponentDidMount() {
    window.addEventListener('online', () => this.props.setConnectivity('online'));
    window.addEventListener('offline', () => this.props.setConnectivity('offline'));

    // You don't need to worry about removeEventlistener if your main App ponent never unmounts.
}

// Action
const setConnectivity = (status) => ({
    type: 'SET_CONNECTIVITY',
    payload: status === 'online'
})

// Reducer
const connectivityReducer = (state = initialState, action) => {
    switch (action.type) {
        case 'SET_CONNECTIVITY':
            return {
                ...state,
                isOnline: action.payload
            };
    }
};

// To let a ponent know about the connectivity status, simply use the flag from state:
const mapStateToProps = (state) => ({
    isOnline: state.connectivity.isOnline
});

// To react to status changes in any other ponent:
ponentDidUpdate(prevProps) {
    const { isOnline } = this.props;

    if (!prevProps.isOnline && isOnline) {
        // We went online
    } else if (prevProp.isOnline && !isOnline) {
        // We went offline
    }
}

I suggest to use this very new library

Then you can use useNetworkStatus to get what you wanted, something like:

import React from 'react';

import { useNetworkStatus } from 'react-adaptive-hooks/network';

const MyComponent = () => {
  const { effectiveConnectionType } = useNetworkStatus();

  let media;
  switch(effectiveConnectionType) {
    case 'slow-2g':
      media = <img src='...' alt='low resolution' />;
      break;
    case '2g':
      media = <img src='...' alt='medium resolution' />;
      break;
    case '3g':
      media = <img src='...' alt='high resolution' />;
      break;
    case '4g':
      media = <video muted controls>...</video>;
      break;
    default:
      media = <video muted controls>...</video>;
      break;
  }

  return <div>{media}</div>;
};

effectiveConnectionType - will change if the network changes, `

navigator.connection.addEventListener('change', func) - this will also get trigger on online and on offline

Here is a working example of an online / offline status indicator in React+Redux.

The magic es from having a ponent that adds an event listener for the online event in the ponent's ponentDidMount event. Then it dispatches an action via Redux to update the online status in the store. A container ponent (MainContainer in this example) can map the global store state to props, and any presentational ponent can update in response to this property changing.

By the way, if you want to test this online indicator on this page with Chrome: run the snippet, then launch the Dev Tools (F12), then toggle the device toolbar (Ctrl+Shift+M) (or 2nd icon in the top left of the dev tools window), switch to Responsive layout, and toggle the Online / Offline state in the bar (as shown in this picture) as desired:

function rootReducer(currentState, action) {
  currentState = currentState || { status: true }; // Initial State

  switch (action.type) {
    case 'SET_ONLINE_STATUS':
      return { ...currentState, status: action.status };
    default:
      return currentState; // Always return the state
  }
}

// Action Creators:
function setOnlineStatus(status) {
  return { type: 'SET_ONLINE_STATUS', status };
}

// Create Store
var rootStore = Redux.createStore(rootReducer);

// Map state and dispatch to props
function mapStateToProps(state) {
  return {
    status: state.status
  };
}

function mapDispatchToProps(dispatch) {
  return Redux.bindActionCreators({
    setOnlineStatus: setOnlineStatus
  }, dispatch);
}

// Connection indicator pure functional presentational ponent
var ConnectionIndicator = (props) => {
  return (<div>You are: {props.status ? 'online' : 'offline'}</div>);
};

var Main = React.createClass({
  render: function () {
    return (<div>
      <ConnectionIndicator status={this.props.status} />
    </div>);
  }
});

var OnlineWatcher = React.createClass({
  render() { return null; },
  ponentDidMount() {
    window.addEventListener('online', () => {
      this.props.setOnlineStatus(true);
    })
    window.addEventListener('offline', () => {
      this.props.setOnlineStatus(false);
    })
  }
});


// Container ponents (Pass props into presentational ponent)
var MainContainer = ReactRedux.connect(mapStateToProps, mapDispatchToProps)(Main);
var OnlineWatcherContainer = ReactRedux.connect(mapStateToProps,
                                                mapDispatchToProps)(OnlineWatcher);

// Top-Level Component
var App = React.createClass({
  render: function () {
    return (
      <div>
        <MainContainer />
        <OnlineWatcherContainer />
      </div>
    );
  }
});

// Render to DOM
var Provider = ReactRedux.Provider; // Injects store into context of all descendents
ReactDOM.render(
  <Provider store={rootStore}>
    <App />
  </Provider>,
  document.getElementById('container')
);

	
  
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.3.0/react.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.3.0/react-dom.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/redux/3.5.2/redux.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-redux/4.4.5/react-redux.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/babel-polyfill/6.13.0/polyfill.js"></script>
<div id="container">
  <!-- Yield to React -->
</div>

NOTE: In production code, you should also unsubscribe from the online and offline events in the ponentWillUnmount function.

I used this fiddle as a starting point.

Before all, you should have redux store with actions and reducers.You are able to connect every ponent you want to store and use this source of truth. You can find documentations and exampel here https://react-redux.js/introduction/quick-start

Actually you can find example of using online status Integrating Navigator.onLine into React-Redux

when using hooks, this simple solution would work https://github./saulpalv/useOnline

npm i @saulpalv/useonline

use like this

import type { FC } from 'react';
import { useOnline } from '@saulpalv/useonline';

export const DialogNetwork: FC = ()=> {

    const isOnline = useOnline();

    return (
        <Dialog show={!isOnline}>
            You are not online
        </Dialog >
    );
});
发布评论

评论列表(0)

  1. 暂无评论