React Native Android Fetch failing on connection to local API
Solution 1:
You are not able to access your local development server because that port hasn't been forwarded by ADB yet. When you run react-native run-android
, React Native maps the port 8081 with your mobile device on USB. When you disconnect your USB you won't be able to refresh or hot reload your code anymore. So in this situation you can do 2 things, either map your local server port just like React Native does or use your local IP address.
-
Mapping Port
This only works if you are using Android 6.0+. To forward a port using ADB run the following command in your terminal:
adb reverse tcp:8163 tcp:8163
This will map your local
8163
port to mobile's8163
port. You'll be able to access your development server this way. -
Using local IP address
You can also use your local IP on React Native development app to reload them without USB. Shake your device or long press the menu button to open developer menu. Open
Dev Settings
, then tapDebug server host & port for device
. Here you can enter your machine's local IP with port number8081
. For ex. if your machine's IP is192.168.1.100
then you'd enter192.168.1.100:8081
in here for successful connection. Now we have covered that we can reload the app. After this when you want to use your local machine's development server use the same IP with your server's port number.
You should be good to go with this.
Solution 2:
Run the below command to access localhost or 127.0.0.1 or your computer's ip
adb -s <device_name> reverse tcp:backend_port tcp:backend_port
Example:
adb -s emulator-5554 reverse tcp:3000 tcp:3000
Now, You can use like below in your component.
import React from 'react';
import {View,Image,TextInput, TouchableOpacity, StyleSheet, ImageBackground, AsyncStorage} from 'react-native';
import {Text,Button} from 'native-base';
export class Login extends React.Component{
constructor(props){
super(props);
this.state={username:'',password:''}
}
login = () =>{
fetch('http://localhost:3000/users',{
method:'POST',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
},
body:JSON.stringify({
username:this.state.username,
password:this.state.password
})
})
.then((response)=>response.json())
.then((res)=>{
if(res.success===true){
var username=res.message;
AsyncStorage.setItem('username',username);
this.props.navigation.navigate('app');
alert("Login success");
} else{
alert("Invalid Credentials");
}
})
.done();
}
render(){
return (
<View style={styles.content}>
<Text style={styles.logo}>- WELCOME -</Text>
<View>
<TextInput underlineColorAndroid='transparent' style={styles.input} placeholder="Username"
onChangeText={(username)=>this.setState({username})}
value={this.state.username}>
</TextInput>
<TextInput secureTextEntry={true} underlineColorAndroid='transparent' style={styles.input} placeholder="Password"
onChangeText={(password)=>this.setState({password})}
value={this.state.password}>
</TextInput>
</View>
<TouchableOpacity onPress={this.login} style={styles.buttonContainer}>
<Text style={styles.buttonText}>LOGIN</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container:{
flex:1,
},
content:{
opacity:0.9,
backgroundColor:'white',
borderWidth:2,
margin:10,
alignItems: 'center',
},
logo:{
justifyContent: 'center',
alignItems: 'center',
fontSize:45,
color:'black',
textShadowColor:'gray',
textShadowRadius:10
},
input:{
borderRadius:10,
padding:10,
color:'black',
borderWidth:2,
borderColor:'lightgray',
width:200,
margin:5
},
buttonContainer:{
margin:10,
padding:10,
justifyContent: 'center',
alignItems: 'center',
},
buttonText:{
borderRadius:100,
padding:10,
backgroundColor:'magenta',
color:'white',
textAlign:'center',
width:100
}
});
Output: