React Native token issue when submit - react-native

i build an application with reactNative and Expo for front-end and django for back-end
i want take token from AsyncStorage to recognised the user, but the is an errors
Warning: An unhandled error was caught from submitForm(), [ReferenceError: Can't find variable: useState]
when i change the owner id to static value the submit works fine and show the token value on the console log not sure where is the issue exactly
import React, {useState} from 'react';
import { FieldArray, Formik } from "formik";
import axios from "axios";
import AsyncStorage from '#react-native-async-storage/async-storage';
import jwt_decode from "jwt-decode";
function AddScreen(props){
const submit = ({ type, category, amount }) => {
//here you define the token to be set
const [token, setToken] = useState();
//here you get the token from AsyncStorage
const getToken = async () => {
try {
const data = await AsyncStorage.getItem('token');
if (data !== null) {
setToken(data)
return data;
}
} catch (error) {
console.log(error);
}
};
//here you set the token
getToken()
//here you decode the token
const tokens = token;
const decoded = jwtDecode(tokens);
//here you get the id and it returns a number
const id = decoded.user_id
const config = {
headers: {
"Content-Type": "application/json",
},
};
const date = Date.now();
const owner = id;
const body = JSON.stringify({ type, category, amount, date, owner });
if (type == "" || category == "" || amount == "") {
alert("Please Enter all details");
return;
}
// 'http://192.168.8.143:8000/transactions/'
axios
.post("http://192.168.8.143:8000/transactions/", body, config)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
};
return (
<View style={{ flex: 1, backgroundColor: COLORS.gray }}>
<Formik
initialValues={{ type: "", category: "", amount: "" }}
onSubmit={(values) => {
submit(values);
}}
>
{(props) => (
<View style={styles.whitecard}>
<TextInput
style={styles.inputstyle}
placeholder="type"
onChangeText={props.handleChange("type")}
value={props.values.type}
/>
<TextInput
style={styles.inputstyle}
placeholder="category"
onChangeText={props.handleChange("category")}
value={props.values.category}
/>
<TextInput
style={styles.inputstyle}
placeholder="amount"
onChangeText={props.handleChange("amount")}
value={props.values.amount}
keyboardType="numeric"
/>
<View
style={{
margin: 10,
padding: 0,
backgroundColor: COLORS.pink,
borderRadius: 6,
}}
>
<Button
title="Submit"
color="white"
onPress={props.handleSubmit}
></Button>
</View>
</View>
)}
</Formik>
</View>
);
};
...
export default AddScreen;
the error show
Warning: An unhandled error was caught from submitForm(), [Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.]

You are not importing UseState from React. Also you need to convert your code into a react functional component.
EDIT
For your new error, you need to move the useState out of submit. It must be at the root level of the functional component. I am updating the code example below as well.
import React, {useState} from 'react';
//All your other imports
function AddScreen(props) {
const [token, setToken] = useState(null);
//Everything else remains same inside
};

Related

trigger fetching and updating parent data from separated component using userContext in react native

enter image description here
Above is the image description of what I want to achieve. I already implemented all the layers but I have a problem in automatically updating userContext. I have to refresh the userContext.js page manually to all the information across the app get updated as I want.
My DataBase.js looks like this
import React, { createContext, useState, useEffect,useCallback} from "react";
// create context
const UserContext = createContext();
const UserContextProvider = ({children}) => {
// the value that will be given to the context
var data = global.userSignedUp
const [UserDetails, SetUserDetails] = useState(data)
const [loadingUser, setLoadingUser] = useState(true);
// fetch a user from a fake backend API
const fetchUser = async () => {
// this would usually be your own backend, or localStorage
// for example
var name = global.userSignedUp.username
var index= global.userSignedUp.id
console.log('This the response from DataBase.js',UserDetails)
const data= await fetch('XXXXXX/api/userprofile/'+UserDetails.id+'/',{
method : 'GET',
header : {
Accept : 'application/json',
'Content-Type' : 'application/json'
}
}).then(async res =>{
const response =await res.json()
console.log('This the response from DataBase.js',response)
SetUserDetails(response)
})
//
};
useEffect(() => {
fetchUser();
}, []);
return (
// the Provider gives access to the context to its children
<UserContext.Provider value={[UserDetails, SetUserDetails]}>
{children }
</UserContext.Provider>
);
};
export { UserContext, UserContextProvider };
I defined one global variable index that get updated depending on the user ID from the sign in page and passed inside the Database.js
const onSignInPressed =(logindata)=>{
const username = logindata.username
const password =logindata.password
// state={
// credentials :{username : username, password: password}
// }
fetch('http://XXXXX/auth/',{
method:'POST',
headers:{'Content-Type':'application/json'},
body : JSON.stringify({username:username, password:password})
}).then (async data =>{
const DataResponse =await data.json()
//console.log(DataResponse)
if (data.status===200){
fetch('http://XXXX/api/userprofile',{
method : 'GET',
header : {
Accept : 'application/json',
'Content-Type' : 'application/json'
}
}).then(async res =>{
const response =await res.json()
for (let i=0; i < response.length;i++){
if (response[i].user=== username){
userSignedUp=response[i]
console.log('this is the user Signed up Id',userSignedUp)
navigation.navigate('HomeProfile')
;
}
}
})
}
else{
Alert.alert('Invalid User!','Username or password is incorrect,')
}
})
}
in my HomeProfile.js I can get all the data from UserContext and it workds fine.
Now in my EditProfile.js I have this :
import React , {useState,useContext,useEffect,useCallback} from 'react'
import {SocialIcon} from 'react-native-elements'
import { ImageBackground, View, Text, Image, StyleSheet, useWindowDimensions,Alert} from 'react-native'
import { icons,images, COLORS, SIZES } from '../constants';
import {CustomInput} from '../Component/CustomInput';
import CustomButton from '../Component/CustomButton';
import {useNavigation} from '#react-navigation/native';
import {useForm, Controller} from 'react-hook-form';
import { UserContext, UserContextProvider } from "./MobileDatabase/DataBase";
const EditProfile = () => {
return (
<UserContextProvider>
<EditProfilePage />
</UserContextProvider>
);
}
const EditProfilePage = () => {
const {control,handleSubmit,watch} = useForm();
const {height}= useWindowDimensions();
const navigation =useNavigation();
const newpwd = watch('NewPassword')
const [UserDetails, SetUserDetails]= useContext(UserContext);
let OldUsername=UserDetails.user
let DataFromServer=UserDetails
const onSavePressed = async (EditData) =>{
console.log(EditData)
const uploadData =new FormData();
uploadData.append('username',EditData.ChangeUsername)
let editData= await fetch('http://192.168.56.1:8000/api/users/'+OldUsername+'/',{
method:'PATCH',
headers:{Accept: 'application/json',
'Content-Type': 'multipart/form-data; '},
body :uploadData,
})
let EditDataResponseJson = await editData.json();
console.log(EditDataResponseJson)
SetUserDetails({...UserDetails, user:EditDataResponseJson.username})
UserContextProvider(EditDataResponseJson)
navigation.navigate('HomeProfile')
}
return (
<View style={styles.root}>
<Image
source ={{uri:UserDetails.Profileimage}}
style={[styles.logo]}
//resizeMode='contain'
/>
<Text style={{fontWeight:'bold',
//position:"absolute",
flex:1,
fontSize: 20,
top:'3%',
maxWidth:200,
alignSelf:'center' }}>{UserDetails.user}</Text>
<CustomInput placeholder ='Change UserName'
name="ChangeUsername"
control={control}
rules={{required: 'Username is required',
minLength:{
value:3,
message :'Username should be at least 3 characters long'
}
}}
// value={username}
// setValue={setUsername}
/>
<CustomInput placeholder= 'Change Password'
name ='NewPassword'
control={control}
rules={{required: 'New password is required'}}
// value={password}
// setValue={setPassword}
secureTextEntry={true}
/>
<CustomInput placeholder= 'Confirm Password'
name ='RepeatNewPassword'
control={control}
rules={{
validate: value => value === newpwd || 'Password do not match'
}}
// value={password}
// setValue={setPassword}
secureTextEntry={true}
/>
<View style ={styles.Signup}>
<CustomButton text= 'Save Changes' onPress={handleSubmit(onSavePressed)} />
</View>
</View>
)
}
const styles = StyleSheet.create({
root :{
//alignItems :'center',
paddingTop :'60%',
flex: 1,
},
cover:{
flex:1,
justifyContent: 'center',
},
logo:{
position :'absolute',
top:'10%',
alignSelf:'center',
justifyContent:'center',
alignItems: 'center',
width: 150,
height: 150,
borderRadius: 400/ 2,
},
Signup:{
marginTop: '20%',
}
})
export default EditProfile
When I update the Username for example, it only changes inside EditPage.js but not in HomeProfile.js event thought I update the SetUserDetails. The only way to see the updated data is to refresh the Database.js.
I am very much stuck since a month now and hope for a help here.
Thank you!!

How to set headers in axios, ReactNative

i build an application, React Native as Frontend and Django as Backend,
i use axios to take data from user then send it to backend it show error Request failed with status code 400
i have used Restful API that build with django and run the server locally,
so i think when i add headers to axios then the API request response without errors
so,How to set headers in axios
the user enter the data through form and send it to the backend
Add.js page with form take data from user send it to the backend
import * as React from "react";
import {View, Text, Image, StyleSheet, Button, TextInput} from "react-native";
import { COLORS, SIZES,FONTS} from '../styles/theme.js';
import { FieldArray, Formik} from "formik";
import axios from 'axios';
const AddScreen =()=>{
const radioopt = [{},{},{},{}];
const submit = (val) => {
if(val.type == "" || val.category == "" || val.amount == ""){
alert("Please Enter all details");
return;
}
// 'http://192.168.8.143:8000/transactions/'
axios.post('http://192.168.8.143:8000/transactions/', {
"id": "1",
"type": val?.type,
"category": val.category,
"amount": val?.amount,
// "owner" : "",
"date" : Date.now(),
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
return(
<View style={{flex: 1, backgroundColor:COLORS.gray}}>
<Formik
initialValues={{type:'',category:'', amount:''}}
onSubmit={(values)=>{submit(values)}}
>
{(props)=>(
<View style={styles.whitecard}>
<TextInput
style={styles.inputstyle}
placeholder='type'
onChangeText={props.handleChange('type')}
value={props.values.type}
/>
<TextInput
style={styles.inputstyle}
placeholder='category'
onChangeText={props.handleChange('category')}
value={props.values.category}
/>
<TextInput
style={styles.inputstyle}
placeholder='amount'
onChangeText={props.handleChange('amount')}
value={props.values.amount}
keyboardType='numeric'
/>
<View style={{margin:10,padding:0, backgroundColor:COLORS.pink, borderRadius:6}}>
<Button title='Submit' color='white' onPress={props.handleSubmit}></Button>
</View>
</View>
)}
</Formik>
</View>
);
}
...
export default AddScreen;
You must pass an object with headers like documentation says: https://axios-http.com/docs/req_config
so your request will be:
axios.post('http://192.168.8.143:8000/transactions/',{formData}, {
//example with bearer token
headers: {
'Authentication': 'Bearer 89324u2jhjwe98'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
You can pass options on third argument. There you can add headers on post method like following:
axios.post('https://example.com', formData, { headers: 'content-type': 'text/json',...otherHeaders })

React Native how to get the local time format of device?

I need to get the time format from local device . And I have tried this "https://www.npmjs.com/package/react-native-device-time-format?activeTab=readme"
And also install the moment API and follow what the document said ,however ,when I tried ,it got an error like "
TypeError: null is not an object (evaluating 'RNDeviceTimeFormat.is24HourFormat')
"
I attached my code ,could you please help me to take a look ? Thank you so much !!
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { is24HourFormat } from 'react-native-device-time-format';
import moment from 'moment'
function TryTime(props) {
const getCurrentHourFormat = async (date) => {
const is24Hour = await is24HourFormat();
return (moment(date).format(is24Hour ? 'HH:mm' : 'h:mm A'));
}
return (
<View style={styles.container}>
<Text>{is24Hour}</Text>
</View>
);
}
const styles = StyleSheet.create({
container : {
flex : 1,
justifyContent : 'center',
alignItems : 'center',
}
})
export default TryTime;
There are a few things wrong with your code: you defined a function getCurrentHourFormat but haven't run it yet, so is24Hour is undefined.
function TryTime(props) {
const [currentTime, setCurrentTime] = useState("");
const getCurrentHourFormat = async (date) => {
const is24Hour = await is24HourFormat();
return (moment(date).format(is24Hour ? 'HH:mm' : 'h:mm A'));
}
useEffect(() => {
(async () => {
const timeNow = await TryTime(Date.now);
setCurrentTime(timeNow);
})();
}, []);
return (
<View style={styles.container}>
<Text>{currentTime}</Text>
</View>
);
}
You might want to check useEffect and how functional component work though

undefined is not an object (evaluating 'Amazon.trim') In react native

I am new to react native. And I have created a form. But now its not sending data to server. when I click on Submit button. its keep throwing error like this
undefined is not an object (evaluating 'Amazon.trim')
so whats wrong with my code please help.
here is my code
export default function Add(props) {
const { navigation } = props
const data = props.route.params.data
const amazonD = data.service_details_data[0] ? data.service_details_data[0].amazon_name : ''
const [AmazonError, setAmazonError] = useState([]);
const [Amazon, setAmazon] = useState(undefined);
const validateInputs = () => {
if (!Amazon.trim()) {
setAmazonError('Please Fill The Input')
return;
}
else
{
//+++++++++++++++++++++++++++++++++=submitting form data to api start+++++++++++++++++++++++++++++++++++
{
const data = props.route.params.data
const phpid = data.service_details_data[0] ? data.service_details_data[0].id : ''
AsyncStorage.multiGet(["application_id", "created_by",'leadTagNumber']).then(response => {
fetch('https://xyztech/Android_API_CI/uploaddata/merchant_service_details', {
method: 'POST',
headers: {'Accept': 'application/json, text/plain, */*', "Content-Type": "application/json" },
// We convert the React state to JSON and send it as the POST body
body: JSON.stringify([{ some data}])
})
.then((returnValue) => returnValue.json())
.then(function(response) {
console.log(response)
Alert.alert("File uploaded");
return response.json();
});
});
// event.preventDefault();
}
//+++++++++++++++++++++++++++++++++submitting form data to api end++++++++++++++++++++++++++++++++++++++
Alert.alert("success")
return;
}
};
const handleAmazon = (text) => {
setAmazonError('')
setAmazon(text)
}
return (
<View style={{flex: 1}}>
<ScrollView style={{flex: 1,}} showsVerticalScrollIndicator={false}>
<TextInput
maxLength={30}
placeholder="Amazon *"
style={styles.inputStyle}
onChangeText={(text)=>handleAmazon(text)}
// value={Amazon}
defaultValue={amazonD}
value = {Amazon} />
<Text style={{color :'red'}}>{AmazonError}</Text>
</ScrollView>
<Button
style={styles.inputStyleB}
title="Submit"
color="#FF8C00"
onPress={() => validateInputs()}
/>
</View>
)
}
please ignore this = I am new to react native. And I have created a form. But now its not sending data to server. when I click on Submit button. its keep throwing error like this
Looks like you set Amazon to undefined in useState and then try to access it.
I have also declared such type of error but I will solve it by in the use state I have kept it empty not giving any value for use state then I will use an empty string then it solves.....

Save react-native-check-box status after reload

I am building a React Native Iphone App.I have a checkbox "Remember me" in Login page, which I want to set to remember the username and password in order to login.I want to save the status of checkbox even after reload(Once it is ticked it should persist till it is ticked-off by the user).Below is my code.
index.js :
import React, { Component } from 'react';
import { View,KeyboardAvoidingView, Text, StyleSheet, Dimensions} from 'react-
native';
import CheckBox from 'react-native-check-box';
import AsyncStorage from '#react-native-community/async-storage';
export default class index extends Component{
constructor() {
super();
this.state = {
status: false
};
toggleStatus = async() =>{
this.setState({
status: !this.state.status
});
AsyncStorage.setItem("myCheckbox",JSON.stringify(this.state.status));
}
}
componentWillMount(){
AsyncStorage.getItem('myCheckbox').then((value) => {
this.setState({
status: (value === 'true')
});
});
}
render() {
return (
<KeyboardAvoidingView
style={{ flex: 1, backgroundColor: 'white', justifyContent: 'flex-end'}}
behavior="padding"
keyboardVerticalOffset={50}
enabled>
<Text>{typeof this.state.status +' : '+ this.state.status}</Text>
<CheckBox
style={{flex: 1,paddingLeft:100,paddingTop:20}}
onClick={()=>{
this.setState({
isChecked:!this.state.isChecked
})
toggleStatus(this)
}}
isChecked={this.state.isChecked}
rightText={"Remember me"}
/>
</KeyboardAvoidingView>
);
}
}
index.navigationOptions = {
headerTitle: ''
};
const styles = StyleSheet.create({
});
I could save the status but not set it after reload.I have tried some techniques using the stackoverflow logics, but dint give me proper result.Can anyone help me to set the checkbox.Thanks in advance.
I think you are making a mistake in your toggle method. async doesn't work here (Also we need to use await with async) you should write your code like this. setState take time to save the state so you need to use its callback function which called after the state saved.
I am showing 2 ways here but I prefer the first one.
toggleStatus =() =>{
this.setState({
status: !this.state.status
}, () => AsyncStorage.setItem("myCheckbox",JSON.stringify(this.state.status)));
}
OR
You can do like
toggleStatus = () =>{
AsyncStorage.setItem("myCheckbox",JSON.stringify(!this.state.status));
this.setState({
status: !this.state.status
});
}