React Native show Homepage if is connected - react-native

How to show React Native Homepage if is connected?
and if is not connected, Show a full screen photo? (with a Condition by NetInfo)
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Text,
View,
NetInfo
} from 'react-native';
function ConnectionOk() {
return (
<View >
<Text >
Welcome to React Native1!
</Text>
<Text >
To get started, edit App.js
</Text>
</View>
);
}
function ConnectionNotOk() {
return (
<View>
<Text>not Connected ...</Text>
</View>
);
}
type Props = {};
export default class App extends Component<Props> {
constructor(props) {
super(props)
this.state = {
isConnected: false,
isMounted: true
};
}
componentDidMount() {
// my way of checking internet, don't use both methods
// this.checkInternetConnection();
// Its good idea to attach event listener here, or in constructor
NetInfo.isConnected.addEventListener(
'connectionChange',
this.handleFirstConnectivityChange
);
};
componentWillUnmount() {
this.setState({
isMounted: false
});
// Its good idea to remove all event listener here
NetInfo.removeEventListener(
'connectionChange',
this.handleFirstConnectivityChange
);
};
checkInternetConnection() {
fetch("https://httpbin.org/ip")
.then(response => response.json())
.then(responseJson => {
//update the state only when component is mounted, else it will throw warning
if (this.state.isMounted) {
this.setState({
isConnected: true
});
}
}).catch(err => {
// No internet, redirect to some action if required
})
};
handleFirstConnectivityChange(isConnected) {
if (isConnected) {
this.setState({
isConnected: true
});
} else {
//redirect to some route if required
return <ConnectionNotOk />;
}
render() {
return this.state.isConnected ? < ConnectionOk /> : < ConnectionNotOk />
}
};
}

You can use some flag variable in component state.
From my experience I can say that NetInfo doesn't always gives correct info. ex Internet data is on but no internet connection, NetInfo will return true.
I handle this case by fetching some http api (say https://httpbin.org/ip) which is light and gives correct info about internet.
Also its a good idea to define,add/remove listeners in their appropriate places instead of render.
Try following:
type Props = {};
export default class App extends Component < Props > {
constructor(props) {
super(props)
this.state = {
isConnected: false,
isMounted: true
};
this.checkInternetConnection = this.checkInternetConnection.bind(this);
this.handleFirstConnectivityChange = this.handleFirstConnectivityChange.bind(this);
}
componentDidMount() {
// my way of checking internet, don't use both methods
// this.checkInternetConnection();
// Its good idea to attach event listener here, or in constructor
NetInfo.isConnected.addEventListener(
'connectionChange',
this.handleFirstConnectivityChange
);
}
componentWillUnmount() {
this.setState({
isMounted: false
});
// Its good idea to remove all event listener here
NetInfo.removeEventListener(
'connectionChange',
this.handleFirstConnectivityChange
);
}
checkInternetConnection() {
fetch("https://httpbin.org/ip")
.then(response => response.json())
.then(responseJson => {
//update the state only when component is mounted, else it will throw warning
if (this.state.isMounted) {
this.setState({
isConnected: true
});
}
}).catch(err => {
// No internet, redirect to some action if required
})
}
handleFirstConnectivityChange(isConnected) {
if (isConnected) {
this.setState({
isConnected: true
});
} else {
//redirect to some route if required
//return <ConnectedNotOk / > ;
}
}
render() {
return (
this.state.isConnected ? <ConnectionOk /> : <ConnectionNotOk />
);
}
}
My full example code.

NetInfo.isConnected.fetch().then(isConnected => {
console.log('First, is ' + (isConnected ? 'online' : 'offline'));
});
function handleFirstConnectivityChange(isConnected) {
console.log('Then, is ' + (isConnected ? 'online' : 'offline'));
if (isConnected == false) {
// your image
}
else{
Actions.HomePage() //if connected go to homepage
}
NetInfo.isConnected.removeEventListener(
'connectionChange',
handleFirstConnectivityChange
);
}
NetInfo.isConnected.addEventListener(
'connectionChange',
handleFirstConnectivityChange
);
i am using react-native-router-flux for redirection

You can achieve it by having isConnected flag in state and using network code set it to true or false dynamically. Then inside the render function use below code
{ this.state.isConnected &&
// Your UI code here
}
I have made some changes in your code. Hope it will help you. Please find complete code below:
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Text,
View,
NetInfo
} from 'react-native';
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
isConnected: false,
isMounted: true
};
}
componentWillMount() {
NetInfo.addEventListener(
'connectionChange',
this.handleFirstConnectivityChange
);
}
componentWillUnmount() {
this.setState({
isMounted: false
});
// Its good idea to remove all event listener here
NetInfo.removeEventListener(
'connectionChange',
this.handleFirstConnectivityChange
);
}
handleFirstConnectivityChange(connectionInfo) {
if(connectionInfo.type && connectionInfo.type != "none"){
this.setState({
isConnected: true
});
}else {
this.setState({
isConnected: false
});
}
}
render () {
return (
<View>
{this.state.isConnected &&
<View >
<Text >
Welcome to React Native1!
</Text>
<Text >
To get started, edit App.js
</Text>
</View>
}
{!this.state.isConnected &&
<View>
<Text>not Connected ...</Text>
</View>
}
</View>
)
}
}

Related

Auto update Net Info status in react-native

I am using https://github.com/react-native-community/react-native-netinfo to check network connection in my react-native app. How can fetch network connection automatically when Network is lost and the Network is back again?
Below is the code I using.
import React, { Component } from 'react';
import NetInfo from '#react-native-community/netinfo'
import { View, Text,StyleSheet,Dimensions } from 'react-native';
export default class NetStatus extends Component {
constructor(props) {
super (props)
this.state = {
isConnected:''
};
}
componentDidMount() {
this.handleConnectivityChange()
}
componentWillUnmount() {
this.handleConnectivityChange()
}
handleConnectivityChange(){
NetInfo.fetch().then(isConnected => {
this.setState({ isConnected:isConnected.isInternetReachable });
console.log('isConnected : ', isConnected);
})
};
render() {
return (
<View>
{this.state.isConnected === true ?
null
:(
<View style={styles.container}>
<Text style={{color:'#FFF'}}>
You are not connected to internet....!
</Text>
</View>
)
}
</View>
);
}
}
How can I get the network status without fetching every time when Network is lost and the Network is back again?
You have to add a listener to NetInfo.
Following code can help you,
const [networkState, setNetworkState] = useState(true);
const onNetworkStateChange = (newState) => {
setNetworkState(newState.isConnected);
if (!newState.isConnected) {
// do anything you want
}
};
const initialCheck = () =>
NetInfo.fetch().then((connectionInfo) => {
setNetworkState(connectionInfo.isConnected);
});
useEffect(() => {
initialCheck();
NetInfo.addEventListener(onNetworkStateChange);
}, []);

react native setInterval cannot read property apply

I am new in react native I am trying to render the count of unread notification for that I called my API in HOC it is working fine for initial few seconds but after that, I started to get the below error
func.apply is not a function
below is my code
import React, { Component } from "react";
import PropTypes from "prop-types";
import { Modal, View } from "react-native";
import { themes } from "./constants";
import { AsyncStorage } from "react-native";
export default (OriginalComponent, animationType) =>
class extends Component {
static propTypes = {
handleFail: PropTypes.func,
theme: PropTypes.string,
visible: PropTypes.bool
};
state = {
modalVisible: true
};
static getDerivedStateFromProps({ visible }) {
if (typeof visible === "undefined") {
setInterval(
AsyncStorage.getItem("loginJWT").then(result => {
if (result !== null) {
result = JSON.parse(result);
fetch(serverUrl + "/api/getUnreadNotificationsCount", {
method: "GET",
headers: {
Authorization: "Bearer " + result.data.jwt
}
})
.then(e => e.json())
.then(function(response) {
if (response.status === "1") {
if (response.msg > 0) {
AsyncStorage.setItem(
"unreadNotification",
JSON.stringify(response.msg)
);
} else {
AsyncStorage.setItem("unreadNotification", 0);
}
}
})
.catch(error => {
alert(error);
// console.error(error, "ERRRRRORRR");
});
} else {
AsyncStorage.setItem("unreadNotification", 0);
}
}),
5000
);
return null;
}
return { modalVisible: visible };
}
handleOpenModal = () => {
this.setState({ modalVisible: true });
};
handleCloseModal = () => {
const { handleFail } = this.props;
this.setState({ modalVisible: false }, handleFail);
};
render() {
const { modalVisible } = this.state;
const { theme } = this.props;
return (
<View>
<Modal
animationType={animationType ? animationType : "fade"}
transparent={true}
visible={modalVisible}
onRequestClose={this.handleCloseModal}
>
<View style={themes[theme] ? themes[theme] : themes.transparent}>
<OriginalComponent
handleCloseModal={this.handleCloseModal}
{...this.props}
/>
</View>
</Modal>
</View>
);
}
};
I have not used getDerivedStateFromProps but, according to the docs, it is called on initial component mount and before each render update.
Thus your code is creating a new interval timer on each update without clearing any of the earlier timers, which could be causing a race condition of some sort.
You may want to consider using the simpler alternatives listed in the docs, or at a minimum, insure that you cancel an interval before creating a new one.

Lodash debounce not working all of a sudden?

I'm using a component I wrote for one app, in a newer app. The code is like 99% identical between the first app, which is working, and the second app. Everything is fine except that debounce is not activating in the new app. What am I doing wrong?
// #flow
import type { Location } from "../redux/reducers/locationReducer";
import * as React from "react";
import { Text, TextInput, View, TouchableOpacity } from "react-native";
import { Input } from "react-native-elements";
import { GoogleMapsApiKey } from "../../.secrets";
import _, { debounce } from "lodash";
import { connect } from "react-redux";
import { setCurrentRegion } from "../redux/actions/locationActions";
export class AutoFillMapSearch extends React.Component<Props, State> {
textInput: ?TextInput;
state: State = {
address: "",
addressPredictions: [],
showPredictions: false
};
async handleAddressChange() {
console.log("handleAddressChange");
const url = `https://maps.googleapis.com/maps/api/place/autocomplete/json?key=${GoogleMapsApiKey}&input=${this.state.address}`;
try {
const result = await fetch(url);
const json = await result.json();
if (json.error_message) throw Error(json.error_message);
this.setState({
addressPredictions: json.predictions,
showPredictions: true
});
// debugger;
} catch (err) {
console.warn(err);
}
}
onChangeText = async (address: string) => {
await this.setState({ address });
console.log("onChangeText");
debounce(this.handleAddressChange.bind(this), 800); // console.log(debounce) confirms that the function is importing correctly.
};
render() {
const predictions = this.state.addressPredictions.map(prediction => (
<TouchableOpacity
style={styles.prediction}
key={prediction.id}
onPress={() => {
this.props.beforeOnPress();
this.onPredictionSelect(prediction);
}}
>
<Text style={text.prediction}>{prediction.description}</Text>
</TouchableOpacity>
));
return (
<View>
<TextInput
ref={ref => (this.textInput = ref)}
onChangeText={this.onChangeText}
value={this.state.address}
style={[styles.input, this.props.style]}
placeholder={"Search"}
autoCorrect={false}
clearButtonMode={"while-editing"}
onBlur={() => {
this.setState({ showPredictions: false });
}}
/>
{this.state.showPredictions && (
<View style={styles.predictionsContainer}>{predictions}</View>
)}
</View>
);
}
}
export default connect(
null,
{ setCurrentRegion }
)(AutoFillMapSearch);
I noticed that the difference in the code was that the older app called handleAddressChange as a second argument to setState. Flow was complaining about this in the new app so I thought async/awaiting setState would work the same way.
So changing it to this works fine (with no flow complaints for some reason. maybe because I've since installed flow-typed lodash. God I love flow-typed!):
onChangeText = async (address: string) => {
this.setState(
{ address },
_.debounce(this.handleAddressChange.bind(this), 800)
);
};

React Native - Component update parent

I'm making an app in react native and I'm facing a little problem.
I finished the first layout and now I want to change the style all over the app with a second layout
This is what I have in my parent.
As you can see I use AsyncStorage to check when you open again the app the last selected layout. It all working perfectly.
export default class Home extends React.Component
{
constructor(props){
super(props);
this.state = {
view:0
}
}
componentWillMount()
{
this.checkStructureView();
}
checkStructureView = async() =>
{
const StructureView = await
AsyncStorage.getItem('#StructureView');
if(StructureView == 1)
{
this.setState({
view:1
})
}
else
{
this.setState({
view:0
})
}
}
render()
{
if(this.state.view == 1)
{
return(
<ChangeView/>
...
)
}
else
{
return(
<ChangeView/>
...
)
}
}
}
And this is my component ChangeView. It's a little bit messy because I have for each button active/inactive styles. This is also working perfectly, but the problem is that when I click on the button to change the layout will not change it, only after I refresh the app.
First I added this inside the parent and after I updated the state, the layout has changed instantly but I have more pages where I need to add this component, that's why I'm using an component.
So my question is how can I update instantly the parent state so my layout changes every time I click on the component button without reloading the app.
import React, { Component } from 'react'
import {
View,
Text,
Image,
TouchableOpacity,
AsyncStorage
} from 'react-native'
export default class ChangeView extends Component {
constructor(props){
super(props);
this.state = {
position: this.props.position,
view:0,
view1:require(`../assets/icons/view1_inactive.png`),
view2:require(`../assets/icons/view2_active.png`)
}
}
componentDidMount()
{
this.checkViewStructure();
}
checkViewStructure = async()=>
{
const StructureView = await AsyncStorage.getItem('#StructureView');
if(StructureView == '0')
{
this.setState({
view1:require(`../assets/icons/view1_inactive.png`),
view2:require(`../assets/icons/view2_active.png`)
})
}
else
{
this.setState({
view1:require(`../assets/icons/view1_active.png`),
view2:require(`../assets/icons/view2_inactive.png`)
})
}
}
changeToList = async() =>
{
const StructureView = await AsyncStorage.getItem('#StructureView');
if(StructureView == '0')
{
await AsyncStorage
.setItem('#StructureView', '1')
.then( () => {
//
})
.catch( () => {
alert('Something happened! Please try again later.');
});
this.setState({
view1:require(`../assets/icons/view1_active.png`),
view2:require(`../assets/icons/view2_inactive.png`)
})
}
}
changeToPics = async() =>
{
const StructureView = await AsyncStorage.getItem('#StructureView');
if(StructureView == '1')
{
await AsyncStorage
.setItem('#StructureView', '0')
.then( () => {
//
})
.catch( () => {
alert('Something happened! Please try again later.');
});
this.setState({
view1:require(`../assets/icons/view1_inactive.png`),
view2:require(`../assets/icons/view2_active.png`)
})
}
}
render()
{
if(this.state.position === 0)
return(
<View style={{alignItems:'flex-end',marginTop:20,marginBottom:10,justifyContent:'flex-end',flexDirection:'row'}}>
<View>
<TouchableOpacity
onPress= {() => this.changeToList()}
>
<Image
source={this.state.view1}
style={{width:15,height:21,margin:5}}
/>
</TouchableOpacity>
</View>
<View>
<TouchableOpacity
onPress= {() => this.changeToPics()}
>
<Image
source={this.state.view2}
style={{width:15,height:21,margin:5}}
/>
</TouchableOpacity>
</View>
</View>
)
else
return null
}
}
The ChangeView component only changes state in that specific component. There are several ways of propagating change to the parent component. One way is to implement an onChange prop for the ChangeView component. Your Home component render function would then look like something like this:
render() {
if(this.state.view == 1) {
return(
<ChangeView onChange={ (view) => this.setState({ view }) } />
...
)
} else {
return(
<ChangeView onChange={ (view) => this.setState({ view }) } />
...
)
}
}
You can read more about props here: https://reactjs.org/docs/typechecking-with-proptypes.html
There are other ways of doing this if you have state handler for your application such as Redux.

React Native setInterval doubles it self after restarting app

All the time setInterval acts as I am expecting except for one instance. If user leaves the app by clicking 'home button' and restarts app by clicking the icon (not by selecting from overview), the old setInterval haven't stopped. It starts over again, and there are now running 2 setIntervals. It goes on and on if I repeat this process and user can end up running hundreds of intervals at the same time.
How do I prevent this? I want to run only one instance of seInterval at the time.
Here's my code:
import React, { Component } from 'react';
import {
AsyncStorage,
Text,
View,
AppState,
} from 'react-native';
import timer from'react-native-timer';
class Code_temp extends Component {
redirect(routeName){
this.props.navigator.push({
name: routeName
});
}
constructor(props){
super(props);
this.state = {
appState: AppState.currentState,
};
}
componentDidMount() {
AppState.addEventListener('change', this._handleAppStateChange);
this.setState({showMsg: true}, () => timer.setInterval(
this, 'hideMsg', () =>{
console.log( 1 );
}, 1000
));
}
componentWillUnmount() {
AppState.removeEventListener('change', this._handleAppStateChange);
}
_handleAppStateChange = (nextAppState) => {
if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
}
this.setState({appState: nextAppState});
};
componentWillMount() {
}
render() {
return (
<View>
<Text>
Test
</Text>
</View>
);
}
}
export default Code_temp
That's because you are not clearing the setInterval when the component is unmounted, also remove 'this' from setinterval arguments
componentDidMount() {
timer.clearInterval('hideMsg');
AppState.addEventListener('change', this._handleAppStateChange);
this.setState({showMsg: true}, () => timer.setInterval(
'hideMsg', () =>{
console.log( 1 );
}, 1000
));
}
componentWillUnmount() {
timer.clearInterval('hideMsg');
};