I'm trying to detect if user is connected to the internet. My problem occurs when user is connected to wifi but still have access to mobile internet, then when user turn off wifi (still connected to mobile internet) isInternetReachable state changes to false and then back to true. Anyone encountered something simiral and got some solution for this? I'm not testing on emulator btw.
export function useNetworkHook() {
const [network, setNetwork] = useState(true);
useEffect(() => {
const unsubscribe = NetInfo.addEventListener(data =>
handleConnectivityChange(data.isConnected),
);
return () => {
unsubscribe;
};
}, []);
function handleConnectivityChange(isConnected: boolean | null) {
if (isConnected === null || isConnected === true) {
setNetwork(true);
} else {
setNetwork(isConnected);
}
}
return {network};
}
Related
I am looking for alternative APIs of NetInfo. I have been trying to use NetInfo API as well as react-native-offline (which uses NetInfo behind the scenes) to check constantly if the user is connected to the internet or not in the app and render network error screen based on that. We are using drawer stack for screens and our app is running on react-native "^0.64.1". But the NetInfo isn't working properly. When the app starts, it detects the internet connection correctly but then if we switch the connection type or disconnect fro app, the state is not updating. I am using useNetInfo() hook to access the states of internet. But the value is not refreshing. The code is attatched here.
import React from 'react';
import NoInternetScreen from './NoInternetScreen';
const ConnectionChecker = ({ children }: { children: any }) => {
const netInfo = useNetInfo();
console.log('NetInfo is: ', netInfo.isConnected);
console.log('NetInfo type: ', netInfo.type);
return netInfo.isConnected ? (
children
) : (
<>
<NoInternetScreen />
</>
);
};
export default ConnectionChecker;
I am wrapping the drawer stack with . Since NetInfo is not refreshing I am trying to find the alternatives of NetInfo. So are there any alternatives for NetInfo which can be used to check the network connection and which work for react-native 0.64.1 ?
You can try #react-native-community/netinfo.
import NetInfo from "#react-native-community/netinfo";
const [isConnected, setIsConnected] = useState(true);
NetInfo.fetch().then(state => {
if (state.isConnected && state.isInternetReachable) {
setIsConnected(true);
} else {
setIsConnected(false);
}
});
useEffect(() => {
const unsubscribe = NetInfo.addEventListener((state) => {
if (state.isConnected && state.isInternetReachable) {
setIsConnected(true);
} else {
setIsConnected(false);
}
});
if (isConnected) {
} else {
unsubscribe();
}
return () => {
unsubscribe();
};
}, []);
Description:
When the app is running in a background state or Locked, When the user unlock or foreground the app, useNetInfo(); hook return as isConnected as false. Even I tried to re-fetch the state still using NetInfo.fetch() return the same state.
It's happening in Android real device connected to Wifi
Package Name:
"#react-native-community/netinfo": "^7.1.2",
Code:
const netInfo = useNetInfo();
const [show, setShow] = useState(false);
useEffect(() => {
setShow(!(netInfo.isConnected && netInfo.isInternetReachable));
}, [netInfo]);
useEffect(() => {
fetchConnection();
}, []);
const fetchConnection = () => {
NetInfo.fetch().then((state: any) => {
setShow(!(state.isConnected && state.isInternetReachable));
});
};
I fixed this issue by reverting the package version into "#react-native-community/netinfo": "5.9.7",
Also, change the androidXCore version into 1.6.0. Now it's working as expected.
Reason:
Due to the hibernation features changes in androidXCore version 1.7.0. Netinfo does not return the state properly if the app is in a hibernation state. Please fix this issue in the upcoming release. Thanks.
add navigation focus event listener and check for network update whenever the screen is focused.
Please try this, it's from the package npm site
useEffect(() => {
const subAppState = AppState.addEventListener("change", async (nextAppState) => {
if (IS_IOS_DEVICE && nextAppState=='active') {
let newNetInfo = await NativeModules.RNCNetInfo.getCurrentState('wifi');
//your code here
}
});
const unsubNetState = NetInfo.addEventListener(state => {
//your code here
});
return () => {
if (subAppState) {
subAppState.remove();
}
unsubNetState();
};
},[]);
I've tried #react-native-community/netinfo to check the internet reachability. But the scenario I want to implement is, suppose if my device is connected to a wifi hotspot from another device and if that device's mobile data is turned off I want to show an offline toast.
componentDidMount() {
NetInfo.addEventListener(status => {
this.props.checkOnlineStatus(
status.isConnected,
status.isInternetReachable
);
this.setState({
isConnected: status.isConnected,
isInternetReachable: status.isInternetReachable
});
});
}
render() {
if (!this.state.isInternetReachable && this.props.isOfflineNoticeVisible) {
return <MiniOfflineSign />;
}
return null;
}
But in this case, when the mobile data of the other device is turned off, it doesn't handle the change.
The non-deprecated way (using functional components) with the #react-native-community/netinfo package is now:
import React, { useEffect } from "react";
import NetInfo from "#react-native-community/netinfo";
useEffect(() => {
return NetInfo.addEventListener(state => {
// use state.isInternetReachable or some other field
// I used a useState hook to store the result for use elsewhere
});
}, []);
This will run the callback whenever the state changes, and unsubscribe when the component unmounts.
These connection types could help: https://github.com/react-native-community/react-native-netinfo#netinfostatetype
Otherwise:
Then to be sure, you are online just implement a fetch with timeout:
export default function(url, options, timeout = 5000) {
return Promise.race([
fetch(url, options),
new Promise((_, reject) => setTimeout(() => reject("timeout"), timeout)),
]);
}
Then use it like this:
fetchWithTimeout(url, options)
.then(resp => {
if (resp.status === 200) {
let json = resp.json().then(j => {
return j;
});
})
.catch(ex => {
// HANDLE offline usage
if (ex === "timeout") return true;
//ANY OTHER CASE RETURN FALSE
return false;
}
async function InternetCheck() {
const connectionInfo = await NetInfo.getConnectionInfo();
if (connectionInfo.type === 'none') {
alert('PLEASE CONNECT TO INTERNET');
} else {
//navigate to page or Call API
}
}
Is this at all possible? I'm currently using react-native-track-player to stream audio files and I would love to be able to store the last position when my users exit the app and resume when they re-open (e.g. similar to how Spotify works)
Right now I'm tracking this info via a simple interval:
this.keepTime = setInterval(async () => {
const state = await TrackPlayer.getState()
if (state == TrackPlayer.STATE_PLAYING) {
const ID = await TrackPlayer.getCurrentTrack()
const position = await TrackPlayer.getPosition()
await AsyncStorage.setItem(ID, String(position))
}
}, 10000)
Problem is, I need to clear the interval when my app moves to the background or else it will crash. I would also much rather only need to call this code once as opposed to periodically if that is possible.
I know I could use headless JS on android but the app is cross platform, so my iOS user experience would be lesser.
Any suggestions?
I think you can use componentWillUnmount() function for this.
You could add a listener to get the App State and then log the position when it goes to background.
class App extends React.Component {
state = {
appState: AppState.currentState
}
componentDidMount() {
AppState.addEventListener('change', this.handleAppStateChange);
}
componentWillUnmount() {
AppState.removeEventListener('change', this.handleAppStateChange);
this.saveTrackPosition();
}
handleAppStateChange = (nextAppState) => {
if (nextAppState.match(/inactive|background/) && this.state.appState === 'active') {
this.saveTrackPosition();
}
this.setState({appState: nextAppState});
}
saveTrackPosition = () => {
if (state == TrackPlayer.STATE_PLAYING) {
const ID = await TrackPlayer.getCurrentTrack()
const position = await TrackPlayer.getPosition()
await AsyncStorage.setItem(ID, String(position))
}
}
}
I'm just trying to check internet connection when app launches and also check internet connectivity before calling HTTP Request.I have seen some example but it's confusing for me.Please guide me.
You can use the NetInfo API from react native.
Here is the example:
componentDidMount() {
NetInfo.isConnected.addEventListener(
'change',
this._handleConnectivityChange
);
NetInfo.isConnected.fetch().done(
(isConnected) => { this.setState({isConnected}); }
);
}
componentWillUnmount() {
NetInfo.isConnected.removeEventListener(
'change',
this._handleConnectivityChange
);
}
_handleConnectivityChange = (isConnected) => {
this.setState({
isConnected,
});
};
render() {
return (
<View style={styles.container}>
<Text>{this.state.isConnected ? 'Online' : 'Offline'}</Text>
</View>
);
}
}
Thereby the above code lets you know if you are having internet before making any api call in your app.
You can refer https://facebook.github.io/react-native/docs/netinfo.html for more.
Here is the example:
import { NetInfo,Alert } from 'react-native';
const netStatus = await NetInfo.fetch()
if (netStatus === 'none' || netStatus === 'NONE') {
Alert.alert("Internet not connected ")
return []
}
There probably is a better way to do this, but you could do a console.log() before the HTTP request and pass in parameters of the API, if you get a result of the title in your console, then you're connected to the internet, otherwise you're not.
You should hook this into your api calls before making them. In such case a higher order function would be useful.
import NetInfo from "#react-native-community/netinfo";
import api from "./MyApi"
//higher order function for api calls
const connectionWrapper = async (errorHandler, apiRequest) => () => {
NetInfo.fetch().then(state => {
return state.isConnected
? errorHandler(state)
: apiRequest()
})
}
//use connection wrapper to build your resource calls
const apiCall = connectionWrapper(
state => ...handleError,
api.resource({ myParams : "myParams"})
)
//now you can reuse api call which should return a promise or anything else that you want
var firstCall = apiCall()
var secondCall = apiCall()
var thirdCall = apiCall()