Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native Android Fetch failing on connection to local API

I'm using the fetch API in my react-native Android app to make requests to a local API. I usually query said API from react web apps at http://localhost:8163.

I'm testing my app on my physical device in debugger mode. I read somewhere that react-native can't query localhost the same way a web app can. Apparently you have to use http://10.0.2.2:[PORT_NUMBER_HERE]/ which is an alias for `http://127.0.0.1:[PORT_NUMBER_HERE] according to the Android emulator docks. I'm not sure if this is what I'm supposed to be doing for testing on a physical device.

My fetch code looks like the following:

fetchToken() {     fetch('http://10.0.2.2:8163/extension/auth', {         method: 'GET',         headers: {             'Accept': 'application/json',             'Content-type': 'application/json'         }     })     .then((response)) => console.log('successful fetchToken response: ', response.json()))     .catch((error) => console.log('fetchToken error: ', error))     .done(); } 

The request always hangs for a while and then reaches the catch block with the unhelpful error TypeError: Network request failed(...). Checking the logs for my local API, they don't register the request at all.

So I have no idea if I'm querying my local API correctly to get the resource that I want, and if I am, I don't know why the fetch is failing.

like image 746
seanchen1991 Avatar asked Nov 14 '15 01:11

seanchen1991


People also ask

How do I get localhost API in React Native?

Using local IP addressShake your device or long press the menu button to open developer menu. Open Dev Settings , then tap Debug server host & port for device . Here you can enter your machine's local IP with port number 8081 .

How do you catch network request failed in React Native?

It's just that simple! Start your app as usual but don't forget to give an IP address and a port, this will help you solve the Network Request Failed error. And on your mobile app, make sure to use the correct URL in your request. Make sure that CORS is enabled on your backend to avoid errors related to CORS.

Can I use fetch in React Native?

Using Fetch​React Native provides the Fetch API for your networking needs. Fetch will seem familiar if you have used XMLHttpRequest or other networking APIs before. You may refer to MDN's guide on Using Fetch for additional information.


2 Answers

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.

  1. 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's 8163 port. You'll be able to access your development server this way.

  2. 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 tap Debug server host & port for device. Here you can enter your machine's local IP with port number 8081. For ex. if your machine's IP is 192.168.1.100 then you'd enter 192.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.

like image 158
Jagjot Avatar answered Sep 23 '22 09:09

Jagjot


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:

enter image description here enter image description here

like image 23
VenkateshMogili Avatar answered Sep 24 '22 09:09

VenkateshMogili