React Native - fetch to setState returns the old value - react-native

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]);

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]);

Error: Too many re-renders. React limits the number of renders to prevent an infinite loop React Native with FlatList render

I don't understand why I get this error, when rendering screen I use useSelector to get state from store(I'm using redux) I get data from api and pass it to flatList to render the list, everything is normal but I don't know why
const HistoryScreen = () => {
const { loading, histories } = useSelector((state) => state.historiesList)
useEffect(() => {
if (user) {
dispatch(listHistory())
}
}, [dispatch, user])
return (
<FlatList data={histories} renderItem={({ item, i }) => <HistoryCard key={i} onPress={() => console.warn('cliecked')} post={item} ></HistoryCard>}>
</FlatList >
</View >}</>
)
}
export default HistoryScreen
action:
export const listHistory = (skip = 0, limit = 10) => async (dispatch, getState) => {
try {
dispatch({ type: HISTORY_LIST_REQUEST })
const user = await AsyncStorage.getItem('userInfo')
const userInfo = user ? JSON.parse(user) : null
const config = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const payload = { skip: skip, limit: limit }
const { data } = await axios.post(`${api}/histories/`, payload, config)
dispatch({ type: HISTORY_LIST_SUCCESS, payload: data.data })
console.log(data.data)
} catch (error) {
dispatch({ type: HISTORY_LIST_FAILED, payload: error })
}
}

Unable to set state from the response of the api

I have a following function in Api.js
const _getCategories = async () => {
var categories = [];
let token = await getJwt();
var config = {
method: 'get',
url: 'myurl',
headers: {
'Authorization': 'Bearer' + ' ' + token
},
data : ''
};
axios(config)
.then(function (response) {
if(response.status == 200)
{
let res = response.data;
// Create a variable having name in the list.
categories = res.data.apps.map(function(item) {
return {
title: item.name,
color: AppStyles.colorSet.analyticsColor,
lightColor: AppStyles.colorSet.analyticsLightColor,
icon: AppStyles.iconSet.analytics
};
});
// console.log('Returning Categories');
console.log(categories);
return categories;
//console.log(data1)
// Handle and fetch the list of apps
}
else
{
// API didn't go through, generate the error functions
}
})
.catch(function (error) {
console.log(error);
});
};
and I am loading it in homscreen.js
class DashboardScreen extends React.Component {
constructor(props) {
super(props);
const { navigation } = props;
navigation.setOptions({
title: 'Dashboard',
headerLeft: () => (
<TouchableOpacity
onPress={() => {
navigation.openDrawer();
}}
>
<Icon
style={AppStyles.styleSet.menuButton}
name="ios-menu"
size={AppStyles.iconSizeSet.normal}
color={AppStyles.colorSet.mainThemeForegroundColor}
/>
</TouchableOpacity>
),
});
this.state = {
categories: [],
};
}
componentDidMount() {
if (!this.state.data) {
Api.getCategories().then(data => console.log("The data is "+data))
.catch(err => { /*...handle the error...*/});
}
}
onPressCategory = item => {
// Handle onpress for the items
};
render() {
//console.log(this.state.categories);
categoryButtonsRow1 = this.state.categories.map((item, index) => {
if (index < 3) {
return (
<CategoryButton
onPress={() => this.onPressCategory(item)}
color={item.color}
lightColor={item.lightColor}
icon={item.icon}
title={item.title}
/>
);
}
});
return (
<ScrollView style={styles.container}>
<View style={styles.row}>{categoryButtonsRow1}</View>
</ScrollView>
);
}
}
But I am getting category as undefined while printing in render().
I even tried to create an async function in the homescreen.js and call the api with await and set the state after the same but still it is coming as undefined.
Any guesses to what I am doing wrong here. Can anyone help with the same. My best guess is that I am not handling the api request properly.
EDIT
I tried Use Async/Await with Axios in React.js but it is still printing undefined to the same.
The reason for getting undefined is the _getCategories is that its not returning anything and you are chaining using .then to get data so the caller has no way to get this data as a callback is not passed.
You can change the to await like this
const _getCategories = async () => {
var categories = [];
let token = await getJwt();
var config = {
method: 'get',
url: 'myurl',
headers: {
Authorization: 'Bearer' + ' ' + token,
},
data: '',
};
const response = await axios(config);
if (response.status == 200) {
let res = response.data;
// Create a variable having name in the list.
categories = res.data.apps.map(function (item) {
return {
title: item.name,
color: AppStyles.colorSet.analyticsColor,
lightColor: AppStyles.colorSet.analyticsLightColor,
icon: AppStyles.iconSet.analytics,
};
});
// console.log('Returning Categories');
console.log(categories);
return categories;
//console.log(data1)
// Handle and fetch the list of apps
} else {
// API didn't go through, generate the error functions
return null;
}
};
And you can set the state in componentDidMount (should be async)
this.setState({categories:await api._getCategories()});

fetching values from server for multiselect picker react native

I tried fetching values from server for multi select picker component from the package https://github.com/toystars/react-native-multiple-select. But i get an error message: TypeError: null is not an object(evaluating this.state.LangKnown).
Please Kindly help.Thank u
My JSON values
{
"MFBasic": {
"SkinTones": "DARK,FAIR,VFAIR",
"Build": "SLIM,ATHLETIC,PLUMPY",
"Gender": "F,M,T",
"Genre": "ACTION,COMEDY,DRAMA",
"Languages": "ENG,HINDI,TAM",
"MediaModes": "ADS,MOVIES,SHORTFILMS",
"Tags": "BIKES,HOME,JEWELLARY"
},
"Result": "Successfully Loaded MF Basic Details",
"Code": 100
}
import React, {Component} from "react";
import { Text, View, StyleSheet, Picker, Alert } from "react-native";
import MultiSelect from "react-native-multiple-select";
export default class App extends React.Component {
state = {
LangPickerValueHolder: [],
LangKnown: []
}
componentDidMount () {
fetch('https://movieworld.sramaswamy.com/GetMFBasicDetails.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then(response => response.json())
.then(responseJson => {
let langString = responseJson.MFBasic.Languages;
let langArray = langString.split(',');
this.setState({
LangPickerValueHolder: langArray
});
}).catch(error => {
console.error(error);
});
}
render () {
return (
<View style={styles.itemContainer}>
{<MultiSelect
ref={(component) => { this.multiSelect = component; }}
onSelectedItemsChange={(value) =>
this.setState({ LangKnown: value })
}
selectedItems={this.state.LangKnown}
onChangeInput={ (text) => console.log(text)}
displayKey = ''name
submitButtonText="Submit">
{this.state.LangPickerValueHolder.map((item, key) => (
<MultiSelect.Item item = {item} uniqueKey = {key}/>
))}
</MultiSelect>}
</View>
);
}
}
You've made a good attempt at how to set up the MultiSelect however there are a couple of issues that need to be resolved.
If you look at the dependency the data that should be passed to it should be an array of objects. The example gives the object as { id: '92iijs7yta', name: 'Ondo' } We can easily transform your data from an array of strings into an array of objects that match the example.
let LangPickerValueHolder = langArray.map((name, id) => { return { name, id }; });
Using a map we can convert the array.
This would make your componentDidMount look like the following:
componentDidMount () {
fetch('https://movieworld.sramaswamy.com/GetMFBasicDetails.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then(response => response.json())
.then(responseJson => {
let langString = responseJson.MFBasic.Languages;
let langArray = langString.split(',');
let LangPickerValueHolder = langArray.map((name, id) => { return { name, id }; }); // <- here we had the mapping function
this.setState({ LangPickerValueHolder }); // <- save the new array of objects into the state
console.log(langArray);
}).catch(error => {
console.error(error);
});
}
Setting up the MultiSelect component requires a few more changes.
Firstly there is no MultiSelect.Item so the map that you are using to populate the MultiSelect won't work. Instead you need to use the items prop to set the items. Next you need to tell the MultiSelect component the correct uniqueKey prop (which in our case will be id) and set the displayKey correctly.
Here is what your render could look like.
render () {
return (
<View style={styles.container}>
<MultiSelect
ref={(component) => { this.multiSelect = component; }}
onSelectedItemsChange={(value) =>
this.setState({ LangKnown: value })
}
uniqueKey="id"
items={this.state.LangPickerValueHolder}
selectedItems={this.state.LangKnown}
onChangeInput={ (text) => console.log(text)}
displayKey = 'name'
submitButtonText="Submit" />
</View>
);
}
Here is it put together in a snack: https://snack.expo.io/#andypandy/multiselect-with-data-from-api
Here is the code from the snack:
import React from 'react';
import { View, StyleSheet } from 'react-native';
import MultiSelect from 'react-native-multiple-select';
export default class App extends React.Component {
// declaring state like this is absolutely fine, it doesn't need to be in a constructor
state = {
LangPickerValueHolder: [],
LangKnown: []
}
componentDidMount () {
fetch('https://movieworld.sramaswamy.com/GetMFBasicDetails.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then(response => response.json())
.then(responseJson => {
let langString = responseJson.MFBasic.Languages;
let langArray = langString.split(',');
let LangPickerValueHolder = langArray.map((name, id) => { return { name, id }; });
this.setState({
LangPickerValueHolder
});
console.log(langArray);
}).catch(error => {
console.error(error);
});
}
render () {
return (
<View style={styles.container}>
<MultiSelect
ref={(component) => { this.multiSelect = component; }}
onSelectedItemsChange={(value) =>
this.setState({ LangKnown: value })
}
uniqueKey="id" // <- set the value for the uniqueKey
items={this.state.LangPickerValueHolder} // <- set the items you wish to show
selectedItems={this.state.LangKnown}
onChangeInput={ (text) => console.log(text)}
displayKey = 'name' . // <- fix typo here
submitButtonText="Submit" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: 'white',
padding: 8
}
});

Set State Inside Async Function in React Native(Expo)

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
})
})