Getting NetworkError when setup apollo-client headers - react-native

I'm setting up token authentication in apollo-client with react-native, but my app shows NetworkError. It works fine if I remove all authentication settings.
Error screenshot
This is for a local demo app with react-navigation, apollo-client, formik and yup.
App.js
const httpLink = new createHttpLink({
uri: 'http://192.168.0.2/api/graphql'
});
const authLink = setContext((_, { headers }) => {
const authToken = localStorage.getItem('authToken');
return {
headers: {
...headers,
authorization: authToken ? `JWT ${authToken}` : '',
}
}
});
const APIClient = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
});
class App extends Component {
render(){
return (
<ApolloProvider client={APIClient}>
<SafeAreaView style={styles.container}>
<AppContainer />
</SafeAreaView>
</ApolloProvider>
);
}
};
SignInScreen.js
const TOKENAUTH_MUTATION = gql`
mutation SignIn($username: String!, $password: String!){
tokenAuth(username: $username, password: $password){
token
}
}
`;
class SignInForm extends Component{
constructor(props){
super(props);
}
render(){
return(
<View style={styles.container}>
<Text style={styles.label}>Username:</Text>
<TextInput
autoCapitalize='none'
autoFocus={true}
onBlur={this.props.handleBlur('username')}
onChangeText={this.props.handleChange('username')}
style={styles.textInput}
value={this.props.values.username}
/>
<Text style={styles.helpTextInput}>{this.props.errors.username}</Text>
<Text style={styles.label}>Password:</Text>
<TextInput
onBlur={this.props.handleBlur('password')}
onChangeText={this.props.handleChange('password')}
secureTextEntry={true}
style={styles.textInput}
value={this.props.values.password}
/>
<Text style={styles.helpTextInput}>{this.props.errors.password}</Text>
{this.props.isSubmitting ? (
<ActivityIndicator />
) : (
<Button title="Sign In" onPress={this.props.handleSubmit} />
)}
</View>
);
}
}
class SignInScreen extends Component{
static navigationOptions = {
title: "Sign In"
};
_submit(values, actions, mutateFunc){
mutateFunc({
variables: values
});
}
async _onSuccess(dataResult){
await AsyncStorage.setItem('authToken', dataResult.tokenAuth.token);
this.props.navigation.navigate('Questions');
}
_onError(error){
alert("ERROR: " + JSON.stringify(error));
}
render(){
const formValidationSchema = yup.object().shape({
username: yup.string().required().label("Username"),
password: yup.string().required().label("Password")
});
return(
<Mutation
mutation={TOKENAUTH_MUTATION}
onCompleted={dataResult => this._onSuccess(dataResult)}
onError={error => this._onError(error)}>
{(signInMutationFunc, {loading, error, data}) => {
return (
<Formik
initialValues={{
username: '',
password: ''
}}
onSubmit={(values, actions) => this._submit(values, actions, signInMutationFunc)}
validationSchema={formValidationSchema}>
{formProps => {
return(<SignInForm {...formProps} />);
}}
</Formik>
);
}}
</Mutation>
);
}
}
I expected the token was stored and used in header every request (like Apollo docs says).
If I use a basic ApolloClient it works but doesn't use the header
const APIClient = new ApolloClient({
uri: 'http://192.168.0.2/api/graphql'
});
I'm getting same error in Android and IOS devices :'(

Ok
In my example I was working with Apollo Boost. When I use Apollo Client it works.

Related

Warning: Cannot update a component (`ForwardRef(BaseNavigationContainer)`) while rendering a different component (`Context.consumer`)

here my context file
import React from 'react';
import storage from '#helper/storage/user-storage';
export const AuthContext = React.createContext();
class AuthContextProvider extends React.Component{
state = {
user: null,
nigth_mode: false,
token: null
}
login = async ({user, token}) => {
await storage.storeUser(user)
await storage.storeToken(token)
this.setState({
user: user,
token: token
})
}
logout = async () => {
storage.removeAll().then(() => {
this.setState({
user: null,
token: null
})
});
}
setUser = async (data) => {
this.setState({
user: data
})
}
nigth_mode = async () => {
this.setState({
nigth_mode: !nigth_mode
})
}
render(){
return(
<AuthContext.Provider
value={{
...this.state,
login: this.login,
logout: this.logout,
setUser: this.setUser,
nigth_mode: this.nigth_mode,
token: this.state.token
}}
>
{ this.props.children }
</AuthContext.Provider>
);
}
}
export default AuthContextProvider
in my login file i have this render
render(){
return(
<AuthContext.Consumer>
{context => {
console.log('token', context)
if(context.token){
// this.props.navigation.reset({
// index: 0,
// routes: [{ name: 'Home' }],
// });
this.props.navigation.navigate('View')
}else{
return(
<LinearGradient
colors={['#232526', '#182848']}
style={styles.mainContainerLogin}>
<KeyboardAvoidingView
style={styles.mainContainerLogin}
behavior={'height'}
>
{/* <View style={styles.loginLogo}>
<Image
source={require('../Images/ic-logo.jpg')}
style={styles.logo}
/>
</View> */}
<View style={styles.inputContainer}>
<Ionicon
name="md-person"
size={20}
color="rgb(110,182,245)"
style={styles.inputIcon}
/>
<TextInput
placeholder={'Email'}
placeholderTextColor={'rgba(255,255,255,0.5)'}
underlineColorAndroid="transparent"
style={styles.loginInput}
onChangeText={value => (this.userref = value)}
/>
</View>
<View style={styles.inputContainer}>
<Ionicon
name="md-lock-closed"
size={20}
color="rgb(110,182,245)"
style={styles.inputIcon}
/>
<TextInput
placeholder="Password"
placeholderTextColor={'rgba(255,255,255,0.5)'}
underlineColorAndroid="transparent"
secureTextEntry={this.state.keyHide}
style={styles.loginInput}
onChangeText={value => (this.password = value)}
/>
<TouchableOpacity
style={styles.btnEye}
onPress={this._showPassword.bind(this)}>
<Ionicon
name={
this.state.press == false ? 'md-eye' : 'md-eye-off'
}
size={20}
color="rgb(110,182,245)"
/>
</TouchableOpacity>
</View>
{this._displayLoading()}
{_errorTextLogin(this.state.error)}
</KeyboardAvoidingView>
</LinearGradient>
);
}
}}
</AuthContext.Consumer>
);
so on clicking login button, the context.login is called, so it's set the state of token, so in my condition if my context.token exist i navigate to another page; if i console log on context.token, i got eh token when login is success,then the navigation is processed successfuly but i got a error popup on the new page
Warning: Cannot update a component (`ForwardRef(BaseNavigationContainer)`) while rendering a different component (`Context.consumer`)

How to send bearer token as parameter and retrieve it in another screen in React Native

I want to send bearer token as parameter from one screen and retrieve it another screen and send it too sidebar.
Login.js where i have saved bearer token in const usertoken but can't figure out how to sent it as parameter
import React from 'react';
import {Button,Text,View,Image,TextInput,SafeAreaView,ImageBackground,Alert} from 'react-native';
export default class Login extends React.Component{
constructor(props) {
super(props)
this.state = {
UserName: '',
UserPassword: ''
}
}
UserLoginFunction = () =>{
const { UserName } = this.state ;
const { UserPassword } = this.state ;
fetch('https://api.idepoz.com/ncl/api/login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: UserName,
password: UserPassword
})
}).then((response) => response.json())
.then((responseJson) => {
//console.log(responseJson);
if(responseJson)
{
const usertoken = responseJson.token;
this.props.navigation.navigate({routeName:'QrScan'});
}
else{
Alert.alert(responseJson);
}
}).catch((error) => {
console.error(error);
});
}
}
The following is the screen where i want to retrieve the parameter and navigate it to sidebar
import React from 'react';
import { Container, Header, Title, Drawer, Content, Footer, FooterTab, Button, Left, Right, Body, Text } from 'native-base';
import { Alert } from 'react-native';
import { MaterialIcons } from '#expo/vector-icons';
import { Ionicons } from '#expo/vector-icons';
import SideBar from './components/SideBar';
export default class QrScan extends React.Component{
closeDrawer = () => {
this.drawer._root.close();
}
openDrawer = () => {
this.drawer._root.open();
}
render()
{
return(
<Drawer
ref={(ref) => { this.drawer = ref; }}
content={<SideBar navigator={this.navigator} closeDrawer={this.closeDrawer}/>}
onClose={() => this.closeDrawer()} >
<Container>
<Header>
<Left>
<Button transparent onPress={this.openDrawer.bind(this)}>
<MaterialIcons name="list" size={40} color="#FFFFFF" />
</Button>
</Left>
<Body>
<Title></Title>
</Body>
<Right>
<Button transparent>
<Ionicons name="search" size={40} color="#FFFFFF" onPress={() => Alert.alert('Search Button pressed')} />
</Button>
</Right>
</Header>
<Content>
<Text>
</Text>
</Content>
</Container>
</Drawer>
);
}
}
This is the sidebar.js where i want to retrieve the token and use it to logout
import React from 'react';
import { Text, Alert } from 'react-native';
import { Drawer,Container, Content, Header, Right, Button } from 'native-base';
import { FontAwesome } from '#expo/vector-icons';
export default class SideBar extends React.Component {
render() {
return (
<Container>
<Header>
<Right>
<Button transparent>
<FontAwesome name="close" size={24} color="#FFFFFF" onPress={() => this.props.closeDrawer()} />
</Button>
</Right>
</Header>
<Content>
<Button transparent>
<Text style={{fontSize: 24}}>Log Out</Text>
</Button>
</Content>
</Container>
);
}
}
This is a expo project and i am using react navigation 4.4.3.
you can use redux for sharing data from one component to another
https://react-redux.js.org/introduction/basic-tutorial
I found the answer, In Login.js I stored the bearer token inside UserLoginFunction
UserLoginFunction = () =>{
const { UserName } = this.state ;
const { UserPassword } = this.state ;
fetch('https://api.idepoz.com/ncl/api/login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: UserName,
password: UserPassword
})
}).then((response) => response.json())
.then((responseJson) => {
if(responseJson)
{
this.props.navigation.navigate('QrScan',{usertoken:responseJson.token});
}
else{
Alert.alert(responseJson);
}
}).catch((error) => {
console.error(error);
});
}
In qrscan.js i retrieved the bearer token like this
constructor(props) {
super(props)
this.state = {
token: ''
}
}
componentDidMount(){
this.setState({
token: this.props.navigation.state.params.usertoken,
})
}
Then i send the token again to sidebar like this inside render
render()
{
// const authtoken= this.props.navigation.getParam('usertoken');
//console.log(this.state.token);
return(
<Drawer
ref={(ref) => { this.drawer = ref; }}
content={<SideBar navigator={this.navigator} closeDrawer={this.closeDrawer} usertoken={this.state.token} />}
onClose={() => this.closeDrawer()} >
<Container>
</Container>
</Drawer>
);
}
I retrieved the bearer token in sidebar like this
render() {
console.log(this.props.usertoken);
return ()
}

Multiple prompts AzureAD promptAuthAsync() Expo

I am new here and to Expo/RN. I’m trying to implement some basic authentication in my app with Azure ad to then make Graph API Calls. Right now I have a log in button that is displayed displayed on the WelcomeScreen, however when a user presses it and logs in (via AzureAd prompt), it takes them back to the Welcomescreen until they login again. Its like state isn’t being update or re-evaluated after they login. Am I missing something obvious with promptAsync?
App.js
export default function App() {
const [user, setUser] = useState(null);
WebBrowser.maybeCompleteAuthSession();
const discovery = useAutoDiscovery(
"placeholder"
);
// Request
const [request, response, promptAsync] = useAuthRequest(
{
clientId: "placeholder",
scopes: ["openid", "profile", "email", "offline_access"],
// For usage in managed apps using the proxy
redirectUri: makeRedirectUri({
// For usage in bare and standalone
native: "placeholder",
}),
responseType: ResponseType.Token,
},
discovery
);
const handleLogin = async () => {
await promptAsync();
if (response && response.type === "success") {
var userDecoded = jwtDecode(response.params.access_token);
setUser({
accessToken: response.params.access_token,
userDetails: userDecoded,
});
}
};
return (
<AuthContext.Provider value={{ user, handleLogin }}>
<NavigationContainer theme={navigationTheme}>
{user ? <AppNavigator /> : <AuthNavigator />}
</NavigationContainer>
</AuthContext.Provider>
);
}
(Where login button is)
WelcomeScreen.js
function WelcomeScreen({ navigation }) {
const authContext = useContext(AuthContext);
return (
<ImageBackground
style={styles.background}
source={require("../assets/background.jpg")}
blurRadius={4}
>
<View style={styles.logoContainer}>
<Image source={require("../assets/lo.png")} />
<Text style={styles.titleText}>ITS Inventory</Text>
</View>
<View style={styles.buttonsContainer}>
<AppButton
title={"Login Via Azure"}
style={styles.loginButton}
onPress={() => authContext.handleLogin()}
></AppButton>
</View>
</ImageBackground>
);
}
Thanks!!

Possible Unhandled Promise Rejection (id:0) : ReferenceError: Can't find variable TextInputEmail

import React,{Component} from 'react';
import {View,Text,Image,ImageBackground,
TextInput,TouchableOpacity,AsyncStorage,
ActivityIndicator,StatusBar,StyleSheet} from 'react-native';
import {createStackNavigator} from 'react-navigation-stack' ;
import {createAppContainer,createSwitchNavigator} from 'react-navigation';
import AppContainer from '../App'
import Forgot from '../Screens/Forgot' ;
class Home extends Component {
constructor(props) {
super(props);
this.state = {
TextInputEmail: '',
TextInputPassword: '',
};
}
CheckTextInput = async() =>
{
if (this.state.TextInputEmail != '')
{
if(this.state.TextInputPassword != '')
{
// if(userInfo.TextInputEmail === this.state.TextInputEmail &&
// userInfo.TextInputPassword===this.state.TextInputPassword)
fetch('http://104.197.28.169:3000/auth/login?', {
method: 'POST',
body: JSON.stringify({
"email": TextInputEmail,
"password": TextInputPassword
}),
})
.then((response) => response.json())
.then(() => {
this.props.navigation.navigate('drawernavi')
console.log('response object:',responseJson)
})
.catch((error) => {
console.error(error);
throw error;
});
// await AsyncStorage.setItem('isLoggedIn','1');
// this.props.navigation.navigate('drawernavi')
//this.userLogin()
// alert('Legged in')
// this.userLogin();
}
else
alert('Please Enter Password');
} else
alert('Please Enter Email & Password');
}
render(){
return(
<View>
<ImageBackground style={{width:'100%',height:'100%'}}
source={require('../images/login-screen.png')}>
<View style={{flex:.8,alignItems:'center',justifyContent:'center',marginTop:20}}>
<View style={styles.imageView}>
<Image style={styles.logoImg}
source = {require('../images/core-logo.png')}
></Image>
</View>
<TextInput style={{fontSize:15,borderWidth:1,borderRadius:20,paddingLeft:15,width:300,
borderColor:'black',height:40,marginTop:40}}
keyboardType='email-address'
maxLength={32}
placeholder='Email' placeholderTextColor='#a8a8a8'
onChangeText={TextInputEmail => this.setState({ TextInputEmail })}
value= {this.state.TextInputEmail}
underlineColorAndroid="transparent">
</TextInput>
<TextInput style={{width:300,fontSize:15,borderWidth:1,borderRadius:20,paddingLeft:15,
borderColor:'black',marginTop:20,height:40}}
secureTextEntry={true}
maxLength={14}
placeholder='Password' placeholderTextColor='#a8a8a8'
onChangeText={TextInputPassword => this.setState({ TextInputPassword })}
value= {this.state.TextInputPassword}
underlineColorAndroid="transparent">
</TextInput>
<TouchableOpacity
style={{width:300,marginTop:35,paddingTop:10,paddingBottom:10,backgroundColor:'#2F6995',
borderRadius:20,borderWidth: 1,borderColor: '#fff'}}
onPress={this.CheckTextInput}
underlayColor='#fff'>
<Text style={{color:'#fff',textAlign:'center', paddingLeft : 10, paddingRight : 10,fontSize:17}}>LOGIN</Text>
</TouchableOpacity>
<View style={{alignItems:'center',marginTop:30}}>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('forgotstack')} >
<Text style={{fontSize:12.5,color:'black',borderBottomWidth:1}}> Forgot Password ? </Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>
</View>
);
}
}
i am creating the functionality of login. i got this error while working on it.i am new to this. when i tried to login, the yellow warnings start appearing
i am fetching the data through a node.js api . so it is required that the input field name in api and react is same or it can be different or there is another way, please suggest correct my code if it is wrong
body: JSON.stringify({
"email": TextInputEmail,
"password": TextInputPassword
}),
//Change it to
body: JSON.stringify({
"email": this.state.TextInputEmail,
"password": this.state.TextInputPassword
}),
The problem is if(userInfo.TextInputEmail === this.state.TextInputEmail) in this conditions userInfo is not defined so userInfo.TextInputEmail is not defined .
please check once

How to deal with delay api response in react native using redux?

Im building a react-native app, which when the user try to signIn, I invoike firebase.CreateUser and then an api from firebase function to create that user in my database (Firebase Real-Time). The problem is that when the componentDidUpdate is executed, I still don't have the result from my firebaseFunction, then my props only update if I tap in screen. I would like to know how to deal with that.
Im using redux.
Follow my code:
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, Button, Image,Alert} from 'react-native';
import logo from '../../asserts/logo.png'
import { TouchableOpacity, TextInput } from 'react-native-gesture-handler';
import { Divider,Input} from 'react-native-elements';
import axios from 'axios';
import { connect } from 'react-redux';
import { signupUser} from '../../store/actions/Section/actions';
class Signin extends Component {
state = {
fullName:'',
userName:'',
email:'',
password:'',
confirmPassword:'',
bornDate:'',
State:'',
City:''
};
handleEmailChange = val => {
this.setState({ email:val });
};
handlePasswordChange = val => {
this.setState({ password:val });
};
handleConfirmPasswordChange = val => {
this.setState({ confirmPassword:val });
};
handleNameChange = val => {
this.setState({ fullName:val });
};
handleUserNameChange = val => {
this.setState({ userName:val });
};
handleStateChange = val => {
this.setState({ State:val });
};
handleCityChange = val => {
this.setState({ City:val });
};
handleBornDateChange = val => {
this.setState({ bornDate:val });
};
onSignInUser = () => {
const {email,password} = this.state
if(email=='' || password=='')
return;
this.props.signUp(this.state.fullName,this.state.userName, this.state.email,this.state.password,this.state.confirmPassword,this.state.bornDate,this.state.State,this.state.City);
// this.props.navigation.navigate('User');
};
componentDidUpdate() {
const { idUser, loading,error } = this.props;
console.log(idUser);
console.log('aqui');
if (!loading && error) Alert.alert('Erro', error);
if (!loading && idUser) this.props.navigation.navigate('User');
}
render() {
return (
<View style={styles.container}>
<View style={styles.flexCenter}>
<Image source={logo} style={styles.logoImage}/>
<Text style={styles.logoText} >HomeShare</Text>
<Text style={styles.sublogoText} >SignUp</Text>
</View>
<Divider style={styles.divider} />
<View style={styles.flexButton}>
<View style={styles.inputContainer}>
<Input style={styles.textInput} onChangeText={this.handleNameChange} value={this.state.fullName} placeholder='Nome'/>
<Input style={styles.textInput} onChangeText={this.handleUserNameChange} value={this.state.userName} placeholder='User'/>
<Input style={styles.textInput} onChangeText={this.handleBornDateChange} value={this.state.bornDate} placeholder='Nascimento'/>
<Input style={styles.textInput} onChangeText={this.handleStateChange} value={this.state.State} placeholder='Estado'/>
<Input style={styles.textInput } onChangeText={this.handleCityChange} value={this.state.City} placeholder='Cidade'/>
<Input style={styles.textInput} onChangeText={this.handleEmailChange} value={this.state.email} placeholder='E-mail' keyboardType={'email-address'}/>
<Input style={styles.textInput} onChangeText={this.handlePasswordChange} value={this.state.password} placeholder='Senha' secureTextEntry={true}/>
<Input style={styles.textInput} onChangeText={this.handleConfirmPasswordChange} value={this.state.confirmPassword} placeholder='Confirme sua Senha' secureTextEntry={true}/>
</View>
<TouchableOpacity style={styles.button} activeOpacity={0.5} onPress={this.onSignInUser} >
<View>
<Text style={styles.buttonText}>SignIn</Text>
</View>
</TouchableOpacity>
<Text style={{marginTop:10}}>Ou</Text>
<TouchableOpacity style={styles.button} activeOpacity={0.5} onPress={this.signInUser}>
<View>
<Text style={styles.buttonText}>Entrar com Facebook</Text>
</View>
</TouchableOpacity>
</View>
</View>
);
}
}
const mapStateToProps = ({ section: { restoring, loading, user, error, logged, idUser } }) => ({
restoring: restoring,
loading: loading,
user: user,
error: error,
logged: logged,
idUser: idUser
});
const mapDispatchToProps = {
signUp:signupUser
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(Signin);
My Action:
export const signupUser = (fullName,userName, email,password,confirmPassword,bornDate,State,City) => dispatch => { dispatch(sessionLoading());
firebaseService.auth().createUserWithEmailAndPassword(email, password).then(user => {
console.log(user);
firebaseService.auth().currentUser.getIdToken(true).then(function(idToken) {
SectionService.signIn(idToken,fullName,userName, email,password,confirmPassword,bornDate,State,City).then((response) =>{
console.log(response);
dispatch(sessionSetId(response));
}).catch(e=> {
dispatch(sessionError(e));
});
}).catch(function(error) {
dispatch(sessionError(e));
});
})
.catch(error => {
dispatch(sessionError(error.message));
});
A proposed solution is to handle the account creation in the createUser callback and to update it with other data in the cloud function. Alternatively you can set up a listener that looks for the document, which will then be created and the listener will be notified.
I personally create the user doc on the client side because I create it with some data only available on the client, but your use case will be dictate your preferred approach.