I have a login page. There, the user enters data and submits to the API. The API gives an answer that there is such a user and gives him an id from the database. I write this id in storage.
Next, the user is taken to the home page.
There is a component that is responsible for getting the username (and indeed all other data)
the essence of the component:
1 The parameter receives an id and forms it into a json request.
2 The parameter sends this request to the API and receives the user's data in the response (if the id matches)
3) return which draws the interface and gives the user data from the API response
Problem:
When changing an account (or re-logging in), it gives a json request error (in fact, the API does not accept an empty request, so it rejects it)
The point of getting an ID is 100%. When the application is updated again, the id turns out to be generated in json and after that I already get data about the user.
How to fix it? In fact, it must first receive the id, and only then the id is sent and the data is received, however, at the first entry into the application, he does not want to receive the ID immediately, but only after a reboot (ctlr + s in VS code)
//LOGIN.js
import React, { Component } from 'react';
import { View, Pressable, Text, TextInput, TouchableOpacity } from 'react-native';
import AsyncStorage from '#react-native-async-storage/async-storage';
import styles from './style';
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
email : '',
password : '',
check_textInputChange : false,
secureTextEntry : true,
id : '',
};
}
componentDidMount(){
this._loadInitialState().done();
}
//Сheck that the user with id does not throw out on the authorization screen when exiting the application:
_loadInitialState = async () => {
var id = await AsyncStorage.getItem('id');
if (id !== null) {
this.props.navigation.navigate("HomeScreen")
this.id = id
}
}
InsertRecord () {
var Email = this.state.email;
var Password = this.state.password;
if ((Email.length==0) || (Password.length==0)){
alert("Missing a required field!");
}else{
var APIURL = "http://10.0.2.2:8080/SignIn/login.php";
var headers = {
'Accept' : 'application/json',
'Content-Type' : 'application/json'
};
var Data ={
Email: Email,
Password: Password
};
fetch(APIURL,{
method: 'POST',
headers: headers,
body: JSON.stringify(Data)
})
.then((Response)=>Response.json())
.then((Response)=>{
alert(Response[0].Message)
if (Response[0].Message == "Success") {
console.log(Response[0].Message)
// eslint-disable-next-line react/prop-types
AsyncStorage.setItem('id',Response[0].Id);
this.props.navigation.navigate("HomeScreen");
console.log(Response[0].Id);
}
console.log(Data);
})
.catch((error)=>{
console.error("ERROR FOUND" + error);
})
}
}
updateSecureTextEntry(){
this.setState({
...this.state,
secureTextEntry: !this.state.secureTextEntry
});
}
render() {
return (
<View style={styles.viewStyle}>
<View style={styles.action}>
<TextInput
placeholder="Enter Email"
placeholderTextColor="#ff0000"
style={styles.textInput}
onChangeText={email=>this.setState({email})}
/>
</View>
<View style={styles.action}>
<TextInput
placeholder="Enter Pass"
placeholderTextColor="#ff0000"
style={styles.textInput}
secureTextEntry={this.state.secureTextEntry ? true : false}
onChangeText={password=>this.setState({password})}
/>
<TouchableOpacity
onPress={this.updateSecureTextEntry.bind(this)}>
</TouchableOpacity>
</View>
{/* Button */}
<View style={styles.loginButtonSection}>
<Pressable
style={styles.loginButton}
onPress={()=>{
this.InsertRecord()
}}
>
<Text style={styles.text}>Войти</Text>
</Pressable>
</View>
</View>
);
}
}
//INFOSTATUS.js
import React, { useEffect, useState } from 'react';
import { ActivityIndicator, TouchableOpacity, SafeAreaView, FlatList, StyleSheet, Button, View, Text } from 'react-native';
import { useNavigation } from '#react-navigation/native'
import AsyncStorage from '#react-native-async-storage/async-storage';
function InfoStatus() {
const [isLoading, setLoading] = useState(true);
const [data, setData] = useState([]);
const [idUser, setIdUser] = useState();
//check ID
const idcheck = async () => {
try {
const get = await AsyncStorage.getItem('id')
setIdUser (get)
} catch(e) {
// read error
}
}
//Sending data to api and getting user data
const getNotifications = async () => {
const send = {
id:idUser
}
try {
const response = await fetch('http://10.0.2.2:8080/InfoStatus/InfoStatus.php', {
method: 'POST',
body: JSON.stringify(send),
headers: {
'Content-Type': 'application/json'
}
});
const data = await response.json();
setData(data);
console.log(data);
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
}
useEffect(() => {
idcheck();
getNotifications();
}, []);
//Initialization of received data
const Item = ({ name, middlename,status,number,city }) => (
<View style={StyleInfo.container}>
<View style={StyleInfo.container2}>
<Text style={StyleInfo.TextStyle}> Dear, </Text>
<Text style={StyleInfo.TextStyleData} key ={name}> {name} {middlename} </Text>
</View>
<View style={StyleInfo.container2}>
<Text style={StyleInfo.TextStyle}> Number: </Text>
<Text style={StyleInfo.TextStyleData}key ={number}> № {number} </Text>
<TouchableOpacity
onPress={() =>
navigation.navigate('InfoParser')
}
>
<Text style={StyleInfo.ButtonAdress}>Find out the address</Text>
</TouchableOpacity>
</View>
<View style={StyleInfo.container2}>
<Text style={StyleInfo.TextStyle}> Status: </Text>
<Text style={StyleInfo.TextStyleData} key ={status}> {status} </Text>
</View>
<View style={StyleInfo.container2}>
<Text style={StyleInfo.TextStyle}> City: </Text>
<Text style={StyleInfo.TextStyleData} key ={city}> {city} </Text>
</View>
<TouchableOpacity
style={StyleInfo.Button}
onPress={() =>
navigation.navigate('InfoParser')
}
>
<Text style={StyleInfo.TextButton}>Get contacts of friends</Text>
</TouchableOpacity>
</View>
);
const renderItem = ({ item }) => (
<Item name={item.name} middlename={item.middlename} status={item.status} yik={item.yik} elections={item.elections} />
);
return (
<SafeAreaView>
{isLoading ? <ActivityIndicator size="large" color="#00ff00"/> : (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
)}
</SafeAreaView>
);
}
const StyleInfo = StyleSheet.create({
container:{
width: 390,
height: 190,
borderWidth: 1,
borderRadius: 2,
marginLeft: 10,
marginBottom: 10,
backgroundColor: '#E9E9E9',
},
container2:{
flexDirection: "row",
},
TextStyle: {
fontFamily: 'Raleway',
fontStyle: 'normal',
fontWeight: 'normal',
fontSize: 18,
marginTop: 5,
marginLeft: 5,
bottom: 10,
top: 10
},
TextStyleData: {
fontSize: 18,
marginTop: 5,
top: 10,
fontWeight: 'bold',
},
ButtonAdress: {
fontSize: 18,
marginTop: 5,
marginLeft: 20,
top: 10,
color: "#ff0000",
},
Button: {
width: 310,
height: 40,
marginTop: 10,
marginLeft: 5,
bottom: 10,
borderWidth: 1,
borderRadius: 2,
top: 10,
alignSelf: 'center',
backgroundColor: "#ff0000",
},
TextButton: {
marginTop: 5,
fontSize: 16,
alignSelf: 'center',
fontWeight: 'bold',
color: 'white',
}
}
)
export {InfoStatus}
PS:
I also caught one thing that when I try to get an id via async / await, then most likely the point is that it does not have time to get the value before rendering. I have run out of ideas, I would like to receive more other suggestions
PSS:
I also know that in fact, even if I passed the value through the navigator, I would pass it to the homescreen. Although my InfoStatus is embedded in the Homescreen and I need to somehow pass this parameter there.
Although in general the question interests me a lot, because I will need this parameter everywhere. Therefore, finding one universal solution would be cool.
I am not 100% sure I understand the question so here a few hints I would give you.
You can pass parameters when navigating like this:
navigation.navigate('somescreen', {
param: 86,
otherParam: 'myBestFriendTheParam',
})
On the next screen you have to then read it from the route.params.
You could use redux to have your user data at hand while the app is open and user logged in? That would give you the data where ever you want basically.
If async/wait does not work why don't you use then-chains like in the rest of your code?
Related
I have been trying to create a search bar all day. I finally found this guide which seemed ok: https://blog.jscrambler.com/add-a-search-bar-using-hooks-and-flatlist-in-react-native/. I followed it through using my own API and I am not getting any errors exactly, but the code in this tutorial seems unfinished.
Here is what I have:
import React, { useEffect, useState } from 'react';
import { View, Text, FlatList, SafeAreaView, TextInput } from 'react-native';
import { Card, Header } from 'react-native-elements'
import { styles } from './styles.js';
import filter from 'lodash.filter';
const FormsScreen = ({navigation, route}) => {
const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState([]);
const [query, setQuery] = useState('');
const [fullData, setFullData] = useState([]);
//Fetch all users from database
useEffect(() =>{
setIsLoading(true);
fetch('http://10.0.2.2:5000/forms').then(response =>{
if(response.ok){
return response.json();
}
}).then(data => setFullData(data)).then(setIsLoading(false));
}, []);
function renderHeader() {
return (
<View
style={{
backgroundColor: '#fff',
padding: 10,
marginVertical: 10,
borderRadius: 20
}}
>
<TextInput
autoCapitalize="none"
autoCorrect={false}
clearButtonMode="always"
value={query}
onChangeText={queryText => handleSearch(queryText)}
placeholder="Search"
style={{ backgroundColor: '#fff', paddingHorizontal: 20 }}
/>
</View>
);
}
const handleSearch = text => {
const formattedQuery = text.toLowerCase();
const filteredData = filter(fullData, form => {
return contains(form, formattedQuery);
});
setData(filteredData);
setQuery(text);
};
const contains = ({ ID }, query) => {
console.log("ID was: "+ID);
console.log("Query was: "+query);
const id = ID;
console.log('id was: '+id);
if (id.toString().includes(query)) {
return true;
}
return false;
};
if (isLoading) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="large" color="#5500dc" />
</View>
);
}
else{
return (
<SafeAreaView>
<Header
leftComponent={{ icon: 'menu', color: '#fff' }}
centerComponent={{ text: 'Request Forms', style: { color: '#fff', fontSize: 25} }}
rightComponent={{ icon: 'home', color: '#fff' }}
/>
<FlatList
ListHeaderComponent={renderHeader}
keyExtractor={(item) => item.ID.toString() }
data={fullData}
renderItem={({item}) => (
<Card>
<Card.Title>{item.ID}</Card.Title>
<Card.Divider/>
<View style={styles.Container}>
<Text>{item.Comments}</Text>
{/* <Image source={require('./System apps/Media Manager/Gallery/AppPhotos/45e5cefd-7798-4fe9-88de-86a0a15b7b9f.jpg')} /> */}
<Text>{item.RoadName}</Text>
</View>
<View style={styles.ListContainer}>
<Text style={styles.LabelText}>Name</Text>
<Text style={styles.LabelText}>Phone</Text>
<Text style={styles.LabelText}>Email</Text>
</View>
<View style={styles.ListContainer}>
<Text style={styles.CardText}>{item.Name}</Text>
<Text style={styles.CardText}>{item.Phone}</Text>
<Text style={styles.CardText}>{item.Email}</Text>
</View>
</Card>
)}
/>
</SafeAreaView>
);
}
}
export default FormsScreen;
I have 2 main problems here.
1.) The tutorial had me initialize data and setData. setData is called and it looks to me like that is the final result after the search. The problem is that the author never actually used the variable data so I what do I do with it? Right now the the list is unaltered no matter what happens.
2.) I know he is using a different API so instead of filtering through First name, Last name, and Email I am only searching through ID. In this section of the tutorial:
const contains = ({ name, email }, query) => {
const { first, last } = name;
if (first.includes(query) || last.includes(query) || email.includes(query)) {
return true;
}
return false;
};
How does this code relate first and last to the first and last name values in the data? When I use this code but substitute name with ID and therefor first with id the value of query is correct (19 for example) but the value of ID is 2040 which is not the value I am looking for, but 2040 is the last ID in the database, or in other words the most recently entered row.
This is a sample of my data for reference:
Any help is greatly appreciated.
Please update
data={fullData}
to
data={query ? data : fullData} in flat list props. That should display your filtered data whenever search query updated.
I want to use firebase phone verification without recaptcha in react native. Below is my code. The code is working properly. But I Don't want to use recaptcha. I try deleting it but it gives error. I am new to react native. Please give proper solution of the following problem. My code is given Below Check It and give solution. Thank You
import * as React from 'react';
import { Text, View, StyleSheet, TextInput,Image,TouchableOpacity,ActivityIndicator,Alert } from 'react-native';
import * as FirebaseRecaptcha from "expo-firebase-recaptcha";
import * as firebase from "firebase";
// PROVIDE VALID FIREBASE CONFIG HERE
// https://firebase.google.com/docs/web/setup
const FIREBASE_CONFIG: any = {
};
try {
if (FIREBASE_CONFIG.apiKey) {
firebase.initializeApp(FIREBASE_CONFIG);
}
} catch (err) {
// ignore app already initialized error on snack
}
export default function App() {
const recaptchaVerifier = React.useRef(null);
const verificationCodeTextInput = React.useRef(null);
const [phoneNumber, setPhoneNumber] = React.useState("");
const [verificationId, setVerificationId] = React.useState("");
const [verifyError, setVerifyError] = React.useState<Error>();
const [verifyInProgress, setVerifyInProgress] = React.useState(false);
const [verificationCode, setVerificationCode] = React.useState("");
const [confirmError, setConfirmError] = React.useState<Error>();
const [confirmInProgress, setConfirmInProgress] = React.useState(false);
const isConfigValid = !!FIREBASE_CONFIG.apiKey;
return (
<View style={styles.container}>
<FirebaseRecaptcha.FirebaseRecaptchaVerifierModal
ref={recaptchaVerifier}
firebaseConfig={FIREBASE_CONFIG}
/>
<View style={styles.first}>
<Text style={{color:'white',fontSize:25,fontWeight:'bold'}}>Welcome</Text>
</View>
<View style={styles.second}>
<Text style={{paddingVertical:5}}>Phone No</Text>
<View style={styles.fileds}>
<Image style={styles.logo} source={require('./assets/user.png')} />
<TextInput style={styles.input}
autoFocus={isConfigValid}
autoCompleteType="tel"
keyboardType="phone-pad"
textContentType="telephoneNumber"
editable={!verificationId}
onChangeText={(phoneNumber: string) => setPhoneNumber(phoneNumber)}
/>
</View>
<TouchableOpacity style={styles.button}
disabled={!phoneNumber}
onPress={async () => {
const phoneProvider = new firebase.auth.PhoneAuthProvider();
try {
setVerifyError(undefined);
setVerifyInProgress(true);
setVerificationId("");
const verificationId = await phoneProvider.verifyPhoneNumber(
phoneNumber,
recaptchaVerifier.current
);
setVerifyInProgress(false);
setVerificationId(verificationId);
verificationCodeTextInput.current?.focus();
} catch (err) {
setVerifyError(err);
setVerifyInProgress(false);
}
}}
>
<Text style={{alignSelf:'center',color:'white'}}>{`${verificationId ? "Resend" : "Send"} OTP`}</Text>
</TouchableOpacity>
{verifyError && (
<Text style={styles.error}>{`Error: ${verifyError.message}`}</Text>
)}
{verifyInProgress && <ActivityIndicator style={styles.loader} />}
{verificationId ? (
<Text style={styles.success}>
A verification code has been sent to your phone
</Text>
) : undefined}
<Text style={{paddingTop:25,paddingBottom:5}}>OTP</Text>
<View style={styles.fileds}>
<Image style={styles.logo} source={require('./assets/password.png')} />
<TextInput
ref={verificationCodeTextInput}
style={styles.input}
editable={!!verificationId}
placeholder="123456"
onChangeText={(verificationCode: string) =>
setVerificationCode(verificationCode)
}
/>
</View>
<TouchableOpacity style={styles.button}
disabled={!verificationCode}
onPress={async () => {
try {
setConfirmError(undefined);
setConfirmInProgress(true);
const credential = firebase.auth.PhoneAuthProvider.credential(
verificationId,
verificationCode
);
const authResult = await firebase
.auth()
.signInWithCredential(credential);
setConfirmInProgress(false);
setVerificationId("");
setVerificationCode("");
verificationCodeTextInput.current?.clear();
Alert.alert("Phone authentication successful!");
} catch (err) {
setConfirmError(err);
setConfirmInProgress(false);
}
}}>
<Text style={{alignSelf:'center',color:'white'}}>Confirm OTP</Text>
</TouchableOpacity>
{confirmError && (
<Text style={styles.error}>{`Error: ${confirmError.message}`}</Text>
)}
{confirmInProgress && <ActivityIndicator style={styles.loader} />}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
first: {
height:'30%',
width:'100%',
backgroundColor:'rgb(26, 47, 94)',
justifyContent:'center',
padding:20
},
second:{
paddingVertical:30,
paddingHorizontal:20,
borderTopLeftRadius:15,
borderTopRightRadius:15,
marginTop:-10,
backgroundColor:'white'
},
fileds:{
flexDirection:'row',
borderBottomColor:'grey',
borderBottomWidth:1,
padding:5,
},
logo:{
height:20,
width:20
},
button:{
backgroundColor:'rgb(72, 126, 241)',
padding:10,
borderRadius:10,
marginVertical:15
},
buttontwo:{
borderColor:'rgb(72, 126, 241)',
borderWidth:1,
padding:10,
borderRadius:10,
marginVertical:15
},
input:{
width:'80%'
},
error: {
marginTop: 10,
fontWeight: "bold",
color: "red",
},
success: {
marginTop: 10,
fontWeight: "bold",
color: "blue",
},
loader: {
marginTop: 10,
},
});
I solved it. I have a better way to do this.
and also add SHA-256 fingerprint to your firebase project.
go to -> https://console.cloud.google.com -> select project -> API & SERVICES.
Then search Android Device Verification and enable it.
That's it !!
You can't remove captcha verification using default authentication.
Use anonymous authentication to avoid captcha letters to appear.
https://firebase.google.com/docs/auth/web/anonymous-auth
But You can also make it invisible like this:
window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
"recaptcha-container", {
size: "invisible"
}
);
you can simply use
<FirebaseRecaptchaVerifierModal
ref={/* store ref for later use */}
firebaseConfig={/* firebase web config */}
attemptInvisibleVerification={true} /* this add a true state for the verfication */
/>
So I was making this movie browser project in which I had to fetch data from OMDb API(http://www.omdbapi.com/) and display the data in a Flatlist component.
Although I managed to display 10 results of every movie searched for(as API return 10 items on every call), I added a button that would run a function to send a request again to the API using the page parameter, fetch 10 more results and concatenate the results to the movies.
But as soon as I press the button and run the function, this error appears undefined is not an object (evaluating 'item.Title').
This is my code for the Home Component => Home.js
import React, { useState, useEffect } from 'react';
import { StyleSheet, View, Text, FlatList, TouchableHighlight, Image, Button} from 'react-native';
import { TextInput } from 'react-native-gesture-handler';
import { fetchMovies } from "../api/api";
export default class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
text: "",
movies: null,
};
}
//update search text
componentDidUpdate(prevState) {
if (this.state.text !== prevState.text) {
this.getSearch(this.state.text);
}
}
//get search results from fetchMovies
getSearch = async text => {
const results = await fetchMovies(text)
this.setState({ movies: results });
};
////////////////////////////Function making API call using the page parameter///////////
//loading more movies
handleLoadMore = async() => {
try {
const page = Math.trunc(this.state.movies.length / 10) + 1;
const res = await fetchMovies(this.state.text, page);
this.setState(prevState => ({
movies: prevState.movies.concat(res.movies)
}))
}catch(err){
console.log(err.message);
}
}
//////////////////////////////////////////////////////////
//movie title and poster to render in the flatlist
movieCard = ({ item }) => {
return (
<TouchableHighlight
style={styles.movieCard}
underlayColor="white"
onPress={() => {
this.props.navigation.navigate("Details", {
title: item.title,
id: item.imdbID
});
}}
>
<View>
<Image
style={styles.movieImage}
source={ {uri: item.Poster} }
/>
<View style={{alignItems: 'center'}}>
<Text style={styles.movieTitle}>{item.Title} ({item.Year})</Text>
</View>
</View>
</TouchableHighlight>
);
};
render() {
return(
<View style={styles.container}>
<TextInput
style={styles.searchBox}
autoCorrect={false}
autoCapitalize='none'
autoFocus maxLength={45}
placeholder='Search'
onChangeText={(text) => this.setState({ text })}
value={this.state.text}
/>
{this.state.movies ?
<FlatList
style={styles.movieList}
data={this.state.movies}
renderItem={this.movieCard}
keyExtractor={item => item.Title + item.imdbID}
/>
:
<Text
style={{
alignSelf: 'center',
paddingTop: 150,
justifyContent: 'center',
color: '#8a8787',
fontStyle: 'italic' }}>
search for a movie above...
</Text>
}
<Button
onPress={this.handleLoadMore}
title="Load More"
color="#841584"
/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#DDD',
alignItems: 'center',
},
searchBox: {
fontSize: 20,
fontWeight: '300',
padding: 10,
width: '100%',
backgroundColor: 'white',
borderRadius: 10,
marginBottom: 30
},
movieList: {
flex: 1,
marginHorizontal: 30,
},
movieCard: {
flex: 1,
margin: 5,
padding: 5,
},
movieImage: {
width: '100%',
height: 350,
borderRadius: 10,
alignSelf: 'center',
},
movieTitle: {
marginTop: 10,
fontSize: 20,
color: '#333'
}
});
This is the code for api functions => api.js
const API_KEY = "API_KEY";
//fetch search data from omdb api
export const fetchMovies = async (response, page) => {
const url = `http://www.omdbapi.com/?apikey=${API_KEY}&s=${response}`;
try {
let response = await fetch(url);
if(page) {
response = await fetch(url + `&page=${page}`)
}
const { Search } = await response.json();
return Search;
} catch (err) {
return console.log(err);
}
};
//fetch ID from omdb api
export const fetchById = async id => {
const url = `http://www.omdbapi.com/?apikey=${API_KEY}&i=${id}`;
try {
const response = await fetch(url);
const results = await response.json();
return results;
} catch (err) {
return console.log(err);
}
};
I know solution to this is probably simple but being new to react-native I am not able to figure it out.
regarding FlatList, In docs they apparently pass lambda which returns rendered items to renderItem prop
Also your initialized state.movies is null and i think it should be an empty array
this.state = {
text: "",
movies: [],
};
<FlatList
style={styles.movieList}
data={this.state.movies}
renderItem={({item}) => this.movieCard({item})}
keyExtractor={item => item.Title + item.imdbID}
We been having an issue with our login code. We keep receiving an SyntaxError: JSON Parse Error:
We narrowed down the response error happens during one of the .then(response) lines or in the php code. I'm not sure what I'm doing wrong here. Any help?!
loginScreen.js
login = () =>{
const { UserEmail } = this.state ;
const { UserPassword } = this.state ;
fetch('http://localhost:65535/login.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
user_email: UserEmail,
user_pass: UserPassword
})
//Error within line 59-61 or php
})
.then((response) => response.json())
.then((responseJson) => {
// If server response message same as Data Matched
if(responseJson === 'Data Matched'){
alert("Correct");
} else{
alert("Incorrect");
}
}).catch((error) => {
console.error(error);
});
}
render() {
return (
<View style={styles.container}>
<ScrollView
style={styles.container}
contentContainerStyle={styles.contentContainer}>
<View style={styles.welcomeContainer}>
<Image
source={
__DEV__
? require('../assets/images/HootLogo.png')
: require('../assets/images/robot-prod.png')
}
style={styles.welcomeImage}
/>
</View>
login.php Seems like everything is laid out correctly and works functionaly. I tried changing ' to ` and everything.
<?php
// Importing DBConfig.php file.
include 'DBConfig.php';
// Creating connection.
$con = mysqli_connect($HostName,$HostUser,$HostPass,$DatabaseName);
// Getting the received JSON into $json variable.
$json = file_get_contents('php://input');
// decoding the received JSON and store into $obj variable.
$obj = json_decode($json,true);
// Populate User email from JSON $obj array and store into $email.
$user_email = $obj['user_email'];
// Populate Password from JSON $obj array and store into $password.
$user_pass = $obj['user_pass'];
//Applying User Login query with email and password match.
$Sql_Query = "select * from wp_users where user_email = '$user_email' and user_pass = '$user_pass' ";
// Executing SQL Query.
$check = mysqli_fetch_array(mysqli_query($con,$Sql_Query));
if(isset($check)){
$SuccessLoginMsg = 'Data Matched';
// Converting the message into JSON format.
$SuccessLoginJson = json_encode($SuccessLoginMsg);
// Echo the message.
echo $SuccessLoginJson ;
} else{
// If the record inserted successfully then show the message.
$InvalidMSG = 'Invalid Username or Password Please Try Again' ;
// Converting the message into JSON format.
$InvalidMSGJSon = json_encode($InvalidMSG);
// Echo the message.
echo $InvalidMSGJSon ;
}
mysqli_close($con);
?>
Full JS Code
import React, { Component } from 'react';
import {
AppRegistry,
Image,
Input,
Platform,
Button,
Keyboard,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
TextInput,
View,
} from 'react-native';
import { StackNavigator } from 'react-navigation';
export default class login extends Component {
static navigationOptions= ({navigation}) =>({
title: 'Login',
headerRight:
<TouchableOpacity
onPress={() => navigation.navigate('Home')}
style={{backgroundColor: '#f7f7f7'}}>
</TouchableOpacity>
});
constructor(props){
super(props)
this.state={
userEmail:'',
userPassword:''
}
}
login = () =>{
const { UserEmail } = this.state ;
const { UserPassword } = this.state ;
fetch('http://192.168.0.13:65535/login.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
user_email: UserEmail,
user_pass: UserPassword
})
}).then((response) => response.json())
.then((responseJson) => {
// If server response message same as Data Matched
if(responseJson === 'Data Matched')
{
//Then open Profile activity and send user email to Home After Login.
alert(responseJson);
}
else{
alert(responseJson);
}
}).catch((error) => {
console.error(error);
});
}
render() {
return (
<View style={styles.container}>
<ScrollView
style={styles.container}
contentContainerStyle={styles.contentContainer}>
<View style={styles.welcomeContainer}>
<Image
source={
__DEV__
? require('../assets/images/HootLogo.png')
: require('../assets/images/robot-prod.png')
}
style={styles.welcomeImage}
/>
</View>
<View style={styles.errorContainer}>
<Text style={{padding:10,margin:10,color:'red'}}>{this.state.email}</Text>
</View>
<View style={styles.container}>
<Text style={styles.headerText}>Username</Text>
</View>
<TextInput
placeholder="Enter Email"
style={styles.input}
onChangeText={userEmail => this.setState({userEmail})}
/>
<View style={styles.container}>
<Text style={styles.headerText}>Password</Text>
</View>
<TextInput
placeholder="Enter Password"
style={styles.input}
secureTextEntry
onChangeText={userPassword => this.setState({userPassword})}
/>
<TouchableOpacity style={styles.buttonContainer}
onPress={this.login}>
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
<View style={styles.loginContainer}>
<Text style={styles.loginText}>Don't Have an Account?</Text>
<TouchableOpacity style={styles.emailButtonContainer}
onPress={() => this.props.navigation.navigate('Links')}>
<Text style={styles.loginButtonText}>Register</Text>
</TouchableOpacity>
</View>
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
contentContainer: {
paddingTop: 10,
},
welcomeContainer: {
alignItems: 'center',
},
welcomeImage: {
width: 250,
height: 230,
resizeMode: 'contain',
marginLeft: -10,
},
errorContainer: {
flex: 1,
backgroundColor: '#fff',
marginTop: -55,
alignSelf: 'center',
},
headerText: {
fontSize: 20,
color: 'rgba(96,100,109, 1)',
lineHeight: 24,
marginLeft: 50,
marginBottom: 10,
},
input: {
height: 40,
borderBottomColor: 'rgba(0,0,0,0.4)',
borderBottomWidth: 3,
padding: 10,
marginBottom: 10,
marginHorizontal: 50,
},
buttonContainer: {
backgroundColor: '#78AA3A',
padding: 15,
marginTop: 10,
marginHorizontal: 50,
borderColor: '#fff',
borderRadius:10,
borderWidth: 1,
},
buttonText: {
textAlign: 'center',
color: '#FFFFFF',
},
loginContainer: {
textAlign: 'center',
marginTop: 10,
flexDirection: 'row',
},
loginText: {
marginLeft: 80,
marginBottom: 20,
color: 'rgba(0,0,0,0.4)',
fontSize: 14,
lineHeight: 19,
},
loginButtonText: {
fontSize: 14,
color: '#78AA3A',
paddingLeft: 5
},
});
AppRegistry.registerComponent('login', () => login);
From what I can see the issue is that your PHP server does not return valid json. It returns a string, even though you do json_encode the string, the string will either be "Data Matched" or "Invalid Username or Password Please Try Again". However, when you make the fetch request and do
.then((response) => response.json())
.then((responseJson) => {
It attempts to parse the string "Data Matched" when you do response.json()).then((responseJson) the .json() part is trying to parse the string that is invalid JSON. So you can resolve this in two ways actually send valid json back from the php server build an object like this { "success" : true, message :"Data Matched"} or simply remove the .json() chain, so then javascript will return a string and not try to parse it as JSON. So without the .json() it will be
...
.then((response) => {
// If server response message same as Data Matched
if(response === 'Data Matched')
{
alert(response);
} else {
alert(response);
}
...
Simply try removing .then((response) => response.json() part on line 58 first, and skipping directly to the next chained then clause
i think you need to try change the code
fetch('http://localhost:65535/login.php'....
to your ip, check your local ip using ipconfig
and change the code like this
fetch('http://192.168.1.1/login.php'....
sample ip
Actually I am new to React Native. In my recent project, I have faced an issue while using useMutation hook for updating the data in my server. I have attached the file in which I am using it.
For your reference, I have attached the screenshot of the playground.
Note:- I am not getting an error and the values are not updated in the server. If I click on the button. It is not required to refetch it and display the info using a query, just an update would be enough.
Mutation structure:
.
graphql request sent:
import React, { Component,useState } from 'react';
import { View, Text, StyleSheet, Dimensions,ScrollView,AsyncStorage,TouchableHighlight,Alert,KeyboardAvoidingView} from 'react-native';
import TopHeader from '../../Header/TopHeader';
import { gql } from 'apollo-boost';
import Input from '../../SignIn/Input';
import { ScreenLoader } from '../../Loader';
import { useMutation } from '#apollo/react-hooks';
export const UPDATE_USER_DETAILS = gql`
mutation UpdateUser($input: AccountInput!){
accountUpdate(input: $input){
accountErrors{
message
}
user{
id
email
firstName
lastName
}
}
}
`;
const getToken = async () => {
const token = await AsyncStorage.getItem('token');
console.log("Token = "+token);
return token;
}
function UpdateUserComponent({ firstname,lastname }) {
const [newfirstName, setNewfirstName] = useState(firstname);
const [newlastName, setNewlastName] = useState(lastname);
var token = getToken();
console.log("Inside Update User Component");
const [updateUser,{loading,data,error}] = useMutation(UPDATE_USER_DETAILS,{
headers: {
Authorization: token ? `Bearer ${token}` : ''}
})
if (loading) return <ScreenLoader/>
if (error){
console.log(error);
return <Text>Error...</Text>
}
console.log(data);
return (
<KeyboardAvoidingView style={styles.container} behavior='padding' enabled>
<ScrollView>
<View style={{ paddingTop: 36 }}>
<Input type="text" value={newfirstName} onChange={e => setNewfirstName(e.target.value)} />
<View style={{ paddingTop: 10 }}>
<Input type="text" value={newlastName} onChange={e => setNewlastName(e.target.value)}/>
</View>
<TouchableHighlight underlayColor='#fff' onPress={() => updateUser({ variables: { "input": {"firstName": newfirstName,"lastName": newlastName }} })} >
<View style={{ paddingTop: 50 }}>
<View style={styles.buttonLayout}>
<Text style={styles.buttonText}>Save Changes</Text>
</View>
</View>
</TouchableHighlight>
</View>
</ScrollView>
</KeyboardAvoidingView>
)
}
const width = Dimensions.get('window').width;
class AccountSettings extends Component {
render() {
return (
<View style={{ flex: 1 }}>
<TopHeader text='Account Settings'/>
<UpdateUserComponent/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-start',
alignItems: 'center',
paddingTop: 20,
},
buttonLayout: {
backgroundColor: '#C5C5C5',
width: width * 85 / 100,
height: 45,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 20,
},
buttonText: {
color: '#919191',
fontSize: 14
},
})
export default AccountSettings;
Update:
There is some error in getting the values from Form Input Elements. If I assign values directly it is updating. For Example:- if I use this statement on button press, the data is updated on the server.
onPress={() => UpdateUser({ variables: { "input": {"firstName": "Prabhu","lastName": "Visu" }} }) }
Please help me in fixing this issue, making it work dynamically. Thanks .!
Replace This:
*onChange={e => setNewfirstName(e.target.value)}*
With This:
*onChangeText={text => setNewfirstName(text)}*
It will be working.!