Set State Inside Async Function in React Native(Expo) - react-native

I am using Expo of React Native which i need to save the API Fetch response to state.
My code is like this:
onPress={async () => {
if (this.camera) {
const options = { quality:0, base64: true};
let photo = await this.camera.takePictureAsync(options);
setTimeout(()=>{
fetch('https://c7pl8gkrj6.execute-api.ap-southeast-1.amazonaws.com/prod/rekog', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
base64: photo['base64'],
}),
}).then((responseJson) => {
this.setState({
response:responseJson
})
})
.catch((error) => {
console.error(error);
});
this.setState({captured:true})
}, 3000)
}
}}
I want to store the response in the state variable named 'response'. But When I want to display the response saved in state, it will render null.
if(this.state.captured){
console.log(this.state.response)
return(
<View style={styles.container}>
<SectionList
sections={[
{title: 'response1', data: [this.state.response]}
]}
renderItem={({item}) => <Text style={styles.item}>{item}</Text>}
renderSectionHeader={({section}) => <Text style={styles.sectionHeader}>{section.title}</Text>}
keyExtractor={(item, index) => index}
/>
</View>
);
}else{
...
Here, console.log(this.state.response) shows {} i.e null value. Is it the problem of async function which is not displaying the value saved in state.

No definitely not, as long as your API does return a result, but you should do this.
onPress={async () => {
if (this.camera) {
const options = { quality:0, base64: true};
let photo = await this.camera.takePictureAsync(options);
setTimeout(()=>{
await fetch('https://c7pl8gkrj6.execute-api.ap-southeast-1.amazonaws.com/prod/rekog', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
base64: photo['base64'],
}),
}).then(function(response) {
return response.json()
}).then((responseJson) => {
this.setState({
response:responseJson
})
})
.catch((error) => {
console.error(error);
});
this.setState({captured:true})
}, 3000)
}
}}
You missed a few lines there.

You need to extract the response firstly so you have to write one then before your setState then promise like below where reponse.json() extract the actual response and pass it to the responseJson. Thanks, hope it will usefull for you.
.then(reponse => response.json())
.then((responseJson) => {
this.setState({
response:responseJson
})
})

Related

how to fetch data from Api folder in next.js

I"m facing this problem, I store my submitted data in api folder from a page and i successfully can store it and when i console.log it I can see the data but the problem is when I try fetch it to a page where I want show all this data then I didn't get any result, it's shows empty object:
this is the page from where I submitted data to api folder/page
const handleSubmitAllData = async (e) => {
e.preventDefault();
const allData = {
addStory,
selectedVideoUrl,
};
console.log("AllNftData:", allData);
try {
const { data } = await axios({
url: "/api/uploadNftData",
method: "POST",
data: allData,
});
console.log("response Data", data);
} catch (error) {
console.log("Error", error);
}
router.push("/template/marketplace");
};
this is the api page where store data, when console.log the data i see it that's means it's working
this is code of api page
const { log } = console;
export default function teamAdd(req, res) {
if (req.method === "POST") {
const nftData = req.body;
log("Req payload", nftData);
res.json(nftData);
}
return res.status(500).json({
msg: "this needs to be post request",
});
}
and this is page where I try to fetch this store data from api. this is code , it's not working. I try so many time but it's always comes out with not data
function page() {
const [data, setData] = useState(null);
const [isLoading, setLoading] = useState(false);
const [comments, setComments] = useState([]);
const fetchComments = async () => {
const response = await fetch("/api/uploadNftData");
const data = await response.json();
setComments(data);
console.log(data);
};
useEffect(() => {
setLoading(true);
fetch("/api/uploadNftData", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({}),
})
.then((res) => {
console.log(res);
return res.json();
})
.then((data) => {
console.log(data);
setData(data);
setLoading(false);
})
.catch((error) => {});
}, []);
if (isLoading) return <p>Loading...</p>;
if (!data) return <p>No profile data</p>;
return (
<>
<Main>
<Templatepage>
<TemplateHeader />
<Herosec>
marketplace
<Box
sx={{
background: "#000",
height: "200px",
width: "200px",
margin: "80px",
}}
>
<h1 style={{ color: "#fff" }}>{data.addStory}</h1>
<p style={{ color: "#fff" }}>{data.selectedVideoUrl}</p>
</Box>
</Herosec>
</Templatepage>
</Main>
</>
);
}
What happens if you try to update the dependency array of the useEffect with data
useEffect(() => {
setLoading(true);
fetch("/api/uploadNftData", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({}),
})
.then((res) => {
console.log(res);
return res.json();
})
.then((data) => {
console.log(data);
setData(data);
setLoading(false);
})
.catch((error) => {});
}, [data]);
And I would change the default state of
const [data, setData] = useState(null);
to something more reliable like some custom interface or type.
You can try to verify if data is null in useEffect and then do the request.
It should look something like this:
useEffect(() => {
if(data === null){
setLoading(true);
fetch("/api/uploadNftData", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({}),
})
.then((res) => {
console.log(res);
return res.json();
})
.then((data) => {
console.log(data);
setData(data);
setLoading(false);
})
.catch((error) => {});
}
}, [data]);

React Native - fetch to setState returns the old value

I'm trying to update a row in database with API request Post when click in button (cancel or finish).
The value is update correctly in database but when i click button onPress={() => { settersApi('Finish'); gettersApi(); }} in gettersApi() console.log(estado) return the old value from hook "estado".
export default Home = ({navigation}) => {
const [estado, setEstado] = useState([]);
const gettersApi = async () => {
try {
let response = await fetch(
'http://api/getValues', {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
},
}
);
let json = await response.json();
setEstado(json);
console.log(estado);
} catch (error) {
console.error(error);
}
};
useEffect(() => {
gettersApi();
}, []);
const settersApi = async (param) => {
try {
let response = await fetch(
'http://api/setValues', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
},
body: JSON.stringify({
id: estado.id,
estado: param,
})
}
);
let json = await response.json();
} catch (error) {
console.error(error);
}
};
const CButtons = () => {
return (
<View>
<View>
<Button
color='#ffc107'
title="CANCEL"
onPress={() => {
settersApi('Cancel');
gettersApi();
}}
/>
</View>
<View>
<Button
color='#28a745'
title="FINISH"
onPress={() => {
settersApi('Finish');
gettersApi();
}}
/>
</View>
</View>
);
};
return (
<View style={styles.body}>
<CButtons></CButtons>
</View>
);
};
The function from useState that you called setEtado is a async function. You wont see any changes right away after you change it.
Try to watch the variable state and see when it's updated by using useEffect
useEffect(() => {
console.log(estado);
}, [estado]);

Fetch virtual payment address of users in my react native app

I have integrated react-native-upi-payment in my app. The RNUpiPayment Component calls initializePayment method here which gives only vpa for a default user. How can I give vpa address for many users in my database by fecth api or any other methods? Any methods or suggestions please.
My code is here
<TouchableOpacity
style={styles.payBtn}
activeOpacity={0.5}
onPress={() => {
RNUpiPayment.initializePayment(
{
vpa: '8856452125#ybl', // or can be john#ybl or mobileNo#upi
payeeName: 'Stanlee',
amount: '20',
transactionRef: 'aasf-332-aoei-fn',
},
() => {
console.log('Success');
},
() => {
console.log('Failed');
},
);
}}>
<Text style={styles.payBtnTxt}>PAY</Text>
</TouchableOpacity>
Finally got it!
DriverPaymentFunction = () => {
const {DriverUPI} = this.state;
const {DriverName} = this.state;
fetch('http://ip/appname/payment.php', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
upi_id: DriverUPI,
driver: DriverName,
}),
})
.then((response) => response.json())
.then((responseJson) => {
// If server response message same as Data Matched
if (responseJson === 'Data Matched') {
RNUpiPayment.initializePayment( //Payment API
{
vpa: DriverUPI, // or can be john#ybl or mobileNo#upi
payeeName: DriverName,
amount: '0',
transactionRef: 'AppName Ride Transaction',
},
() => {
console.log('Success');
},
() => {
console.log('Failed');
},
);
} else {
Alert.alert(responseJson);
}
})
.catch((error) => {
console.error(error);
});
};

Objects are not valid as a React child (object with keys) React native

Trying to display Api data with Fetch, wanted to know how can i only bring only 'brand' in the return.Getting Error 'Objects are not valid as a React child: object with keys {all}. If you mean to render a collection of children use an array instead'.
export default App = () => {
const [isLoading, setLoading] = useState(true);
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://', {
method: 'POST',
timeout: 10000,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
})
})
.then((response) => response.json())
// .then((responseData) => { console.log(responseData); })
.then((responseData)=> setData(responseData))
.catch((error) => console.error(error))
.finally(() => setLoading(false)); [fetch, data];
}, []);
return (
<ScrollView>
<View style= {styles.container}>
<Text> {data.data} </Text>
</View>
</ScrollView>
My Sample api return value
Object {
"data": Object {
"all": Array [
Object {
"brand": "A1",
},
Object {
"brand": "B1",
},
Object {
"brand": "C1",
export default App = () => {
const [isLoading, setLoading] = useState(true);
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://', {
method: 'POST',
timeout: 10000,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
})
})
.then((response) => response.json())
// .then((responseData) => { console.log(responseData); })
.then((responseData)=> setData(responseData.data))
.catch((error) => console.error(error))
.finally(() => setLoading(false)); [fetch, data];
}, []);
return (
<ScrollView>
<View style= {styles.container}>
{data.map((value,index)=>(<Text key={index}>{value.brand}</Text>)}
</View>
</ScrollView>
)
}
You should use a map to access an array of objects.
You should add proper keys in response to avoid side effects.

Why can I not call on state in the render of a component after fetching data using fetch with React Native

Fairly new to React. Really new to react native. I know you should be able to reference state object in render method but when I try I get an error that is undefined. "Cant get variable of undefined" I want to set up a page that details each entry by id and the fetch method returns the details regarding each venue. I console this.state.data[0].venueName above and it logs out but when I try to reference it in the component it says its undefined.
class BreweryDetailScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
componentWillMount() {
this.getBrewDeetsHandler();
}
getBrewDeetsHandler = () => {fetch('api url', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
itemID: this.props.navigation.state.params.id
}),
}) .then(res => res.json())
.then(myJson => {
this.setState({
data: myJson
});
console.log(this.state.data[0].venueName)
})
.catch((error) => {
console.error(error);
});
};
render() {
return (
<Text>{this.state.data[0].venueName}</Text>
);
}
}
You should handle the loading phase!
you can try to define an isLoading: true state which will change to false when data have been loaded!
Also please do NOT make API request in componentWillMount() and use componentDidMount() instead!
look at this:
import React, { Component } from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
class BreweryDetailScreen extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
data: []
};
}
componentDidMount() {
this.getBrewDeetsHandler();
}
getBrewDeetsHandler = () => {
fetch('api url', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
itemID: this.props.navigation.state.params.id
})
})
.then(res => res.json())
.then(myJson => {
this.setState({
isLoading: false,
data: myJson
});
console.log(this.state.data[0].venueName);
})
.catch(error => {
console.error(error);
});
};
render() {
if (this.state.isLoading) {
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}}
>
<ActivityIndicator size='large' color='red' />
</View>
);
} else {
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}}
>
<Text>{this.state.data[0].venueName}</Text>
</View>
);
}
}
}
export default BreweryDetailScreen;
Few good practices are,
Don't call API in componentWillMount,
componentWillMount() {
this.getBrewDeetsHandler();
}
To call API make use of componentDidMount,
componentDidMount() {
this.getBrewDeetsHandler();
}
API call is async, you won't be able to get data directly after API call because API call will take some time to execute and till that time your component will get render and you will get undefined error for your state.
You can make use of asyn/await for API call,
getBrewDeetsHandler = async () => {
await fetch('api url', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
itemID: this.props.navigation.state.params.id
}),
}) .then(res => res.json())
.then(myJson => {
this.setState({
data: myJson
}, ()=> console.log(this.state.data[0].venueName));//Callback in setState
})
.catch((error) => {
console.error(error);
});
};
After setting state, you won't be able to do console.log with new state value, because setState is also async, make use of callback in setState to console.log data, as I did above.
When you try to use state, do always check if state value exists,
<Text>{this.state.data && this.state.data[0].venueName}</Text>
because setState is an asynchronous operation and you are trying to access to state immediately after setState. please try this one.
this.setState({
data: myJson
}, () => { console.log(this.state.data[0].venueName); });
the second parameter of 'setState' method is a callback function which will be run after changing the state.