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.
-
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
5 Answers
Reset to default 2Simplified 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 >
);
});