I am trying to do an infinite scroll with flatlist. However, every time I make a function to fetch more data, I have a loop with the same data (3 times). Here is my code without fetch more function. How can I fetch more data by changing the page number and making it an infinite scroll until there is no more data left.
P.S. I have setted up Page state and making it +1, but because state updates >3times, I get unlimited loop again with pages that don't even exist.
export default class List extends React.PureComponent {
constructor(props) {
super(props);
this.fetchData = this._fetchData.bind(this);
this.state = {
isLoading: true,
isLoadingMore: false,
_data: null,
accessToken: ""
};
}
async componentWillMount() {
try {
let accessToken = await AsyncStorage.getItem(ACCESS_TOKEN).then(
JSON.parse
);
if (!accessToken) {
this.redirect("login");
} else {
this.setState({ accessToken: accessToken });
}
} catch (error) {
console.log("Something went wrong");
this.redirect("login");
}
this.fetchData(responseJson => {
const data = responseJson;
this.setState({
isLoading: false,
_data: data
});
});
}
_fetchData(callback) {
fetch(`https://website.com/posts?page=${page}&per_page=10`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Bearer " + this.state.accessToken.token
}
})
.then(response => response.json())
.then(callback)
.catch(error => {
console.error(error);
});
}
Related
am relatively new to async tasks but I cant comprehend why my fetch API wont set my vue variable but on console.log it shows the Variable. I’ve tried Async/Await in vain. See the code segment below on my .vue component.
data(){
return{
pg:’’
}
},
methods:{
insertData(){
this.insertDataAPI()
console.log(this.pg) //THIS GIVES EMPTY STRING INSTEAD OF FETCHED DATA
},
insertDataAPI(){
fetch(‘EndPoint’, {
method:'POST',
headers:{
// some headers
},
body:JSON.stringify({
// some data
})
}).then( res => res.json())
.then(async page =>this.pg = await page //Console.log logs the page fine
// but variable pg is not set
).catch( (err) => {
console.log(err)
});
}
}
async/await is a different handler for promise.then().catch(). As fetch returns a promise you can use both
Option 1, await the fetch:
methods: {
insertData() {
this.insertDataAPI();
console.log(this.pg);
},
insertDataAPI() {
const response = await fetch(‘EndPoint’, {
method:'POST',
headers:{
// some headers
},
body:JSON.stringify({
// some data
})
});
this.pg = response.json();
}
}
Option 2, await the insertDataAPI:
methods: {
async insertData() {
await this.insertDataAPI();
console.log(this.pg);
},
insertDataAPI() {
return fetch(‘EndPoint’, {
method:'POST',
headers:{
// some headers
},
body:JSON.stringify({
// some data
})
}).then(res => res.json())
.then(page => this.pg = page)
.catch( (err) => {
console.log(err)
});
}
}
let's try to read about the way async/ await work
you can try on Axiost lib for easier to fetch APIs
This is strange because postman allows me to make a POST however react does not. the token is valid and when called, the token prints to console
export default class Create extends Component {
//url = 'http://127.0.0.1:5000/wtw/articles/'
constructor(props) {
super(props);
this.state = {
//author?
title: '',
description: '',
//image: ,
//token: null
};
}
handleCreate = async () => {
const { title, description, image } = this.state;
let token = await AsyncStorage.getItem('token');
axios
.post('http://127.0.0.1:5000/wtw/articles/', {
headers: {
Authorization: 'Token ' + token,
},
data: {
title: title,
description: description,
},
})
.then(async (Response) => {
console.log(Response);
})
.catch((err) => {
console.log();
console.log(err);
console.log(token);
});
};
}
I tried to call APP with this code imported from another file and it worked fine:
import FormData from 'FormData';
import AsyncStorage from '#react-native-community/async-storage';
let formData = new FormData();
formData.append('userId', '1'); // < this is what I want to change
formData.append('key', '***'); //my key
export function getScoreFromAPI () {
return fetch('https://www.globalfidelio.com/gfn_arcol/api/transaction.php',{
method : 'POST',
headers : {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data'
},
body : formData
} )
.then((response) => {
return response.json()
})
.catch((error) => console.log("l'erreure est: " + error))
}
but now I want to change my userId from 1 to an constante from Asyncstorage, so I decide to change my code to this:
constructor(props) {
super(props)
this.state = { infos: [], userId: '' }
}
componentWillMount() {
this.getScoreFromAPI().then(data => {
this.setState({ infos: data })
});
console.log(this.state.infos);
AsyncStorage.getItem(USERID_STORED)
.then((data) => {
if (data) {
this.setState({userId:data})
}
});
}
async getScoreFromAPI() {
let formData = new FormData();
formData.append('userId', this.state.userId);
formData.append('key', '***'); //my key
try {
let response = await fetch('https://www.globalfidelio.com/gfn_arcol/api/transaction.php',{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data'
},
body: formData
})
let res = await response.json();
} catch(error) {
console.warn("errors are " + error);
}
};
with a try-catch function but when I call getScoreFromAPI() in ComponentWillMount() I can't setState with received data, I still have an empty array in info:[]
my questions:
how can I replace '1' in userId by a value in asyncstorage in the first file ?
if it isn't possible, what I have do to setState info: [] with my data reveived
I've simplified your code into a promise chain in which calling getScoreFromAPI will execute after getting the userId from AsyncStorage, then storing the response into the infos state, while returning null if there was an error, and logging the error to the console. The data was not previously returned from getScoreFromAPI, so the value would always become null. I have not tested this code, but this should give you a good base to work from:
import FormData from 'FormData';
import AsyncStorage from '#react-native-community/async-storage';
export default class Test {
constructor() {
this.state = {
infos: null,
userId: ''
};
}
componentDidMount() {
AsyncStorage.getItem(this.state.userId)
.then(userID => {
this.setState({ userId: userID || '' });
})
.then(() => {
return this.getScoreFromAPI();
})
.then(data => {
this.setState({ infos: data });
})
.catch(console.error);
}
getScoreFromAPI = () => {
const formData = new FormData();
formData.append('userId', this.state.userId);
formData.append('key', '***'); //my key
fetch('https://www.globalfidelio.com/gfn_arcol/api/transaction.php', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data'
},
body: formData
})
.then(response => {
// use response data here
return response.json();
})
.catch(e => {
console.error(e);
return null;
});
};
}
You're doing your API call before fetching your value from AsyncStorage (I know this is async but it's not very readable if you do it that way).
getScoreFromAPI doesn't return anything, that's why your setState isn't working.
You don't need to use try and catch here, promises have their own error handling mechanism (the .catch() method).
I think callbacks are more readable and lead to less bugs than using .then() in code.
This is how I would do it:
constructor(props)
{
super(props);
this.state = { infos: [], userId: '' };
this.onSuccess = this.onSuccess.bind(this);
this.onFailure = this.onFailure.bind(this);
}
componentWillMount()
{
// Get userID from local storage, then call your API
AsyncStorage.getItem(YOUR_KEY)
.then(userID=> {
if (userID)
{
this.setState({ userId : userID }, () => {
this.getScoreFromAPI(this.onSuccess, this.onFailure);
});
}
});
}
onSuccess(data)
{
this.setState({
infos : data
});
}
onFailure(err)
{
console.warn('Error ' + err);
}
getScoreFromAPI(onSuccess, onFailure)
{
let formData = new FormData();
formData.append('userId', this.state.userId);
formData.append('key', '***'); //your key
fetch('https://www.globalfidelio.com/gfn_arcol/api/transaction.php', {
method : 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data'
},
body: formData
})
.then(res => res.json())
.then(json => {
onSuccess(json);
})
.catch(err => {
onFailure(err);
});
}
It's finally done. I tried this and it worked. Thank you to all of you
this is what I have done:
...
const USERID_STORED = "userid_stored";
const GSM_STORED = "gsm_stored";
...
class ScoreList extends React.Component {
constructor(props) {
super(props)
this.state = { infos: [], userId: '', gsmStored: '', }
}
componentWillMount() {
AsyncStorage.getItem(USERID_STORED)
.then(userId => {
this.setState({ userId: userId});
this.getScoreFromAPI(this.state.userId).then(data => {
this.setState({ infos: data });
});
});
AsyncStorage.getItem(GSM_STORED)
.then(gsmStore => {
this.setState({ gsmStored: gsmStore});
});
}
getScoreFromAPI (userId) {
let formData = new FormData();
formData.append('userId', userId);
formData.append('key', '***');
return fetch('https://***',{
method : 'POST',
headers : {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data'
},
body : formData
} )
.then((response) => {
return response.json()
})
.catch((error) => console.log("l'erreure est: " + error))
};
I'm trying to fetch data from api and I used componentDidMount lifecycle for that, But I have a list in my view which need to be created from that API, so I use map function for received data to get all items and show in render part, But when I run my code I get
this.state.matchInfo.map in not a function
Please help me to solve this problem, I knew that componentDidMount will run after first render so I create an empty state first and hoped that after fetching data, component will render again and will show my data. but it keeps getting me the error
here is my code:
constructor(props) {
super(props);
this.state = {
userName: '',
userToken: '',
userID: '',
firstTime: true,
loading: true,
showAlert : false,
alertType : true,
alertMessage : '',
animatedMatchBtn : new Animated.Value(1),
matchInfo: []
};
}
componentDidMount() {
this._bootstrapAsync(true);
}
_bootstrapAsync = async (timeOutStat = null) => {
const userToken = await AsyncStorage.getItem('userToken');
const userName = await AsyncStorage.getItem('userName');
const userID = await AsyncStorage.getItem('userID');
await this.setState({
userName: userName,
userToken: userToken,
userID: userID,
})
if(timeOutStat) {
this.timeOut = setTimeout(() => {
this.setState({
loading: false,
showAlert: true,
alertType: true,
alertMessage: ErrorList.matchMakingError
});
}, 20000)
}
console.log('token', userToken)
await fetch(getInitUrl('getMatchInfo','',this.props.navigation.getParam('matchID', 0)), {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization : `Bearer ${userToken}`
}
}).then(response => Promise.all([response.ok, response.status ,response.json()]))
.then(([responseOk,responseStatus, body]) => { //
this.setState({loading : false});
clearTimeout(this.timeOut);
if (responseOk) {
console.log('match Info', body);
this.setState({
matchInfo : body
})
} else {
console.log(responseStatus, body);
this.setState({
showAlert : true,
alertType : true,
alertMessage : ErrorList[body.tag]
});
}
})
.catch(error => {
console.error(error);
});
};
render() {
//console.log(puzzleSizes)
let rows = this.state.matchInfo.map((item , index)=>{
return
<MatchDetailBox
/>
})
console.log(rows)
<View>
{rows}
</View>
}
Even though this.setState() is asynchronous, it's not promisified hence it wont't work using promise's .then() or its syntactic sugar async/await. So there's no use for await in front of it. But I guess it creates a one tick delay.
Also why do you have await in front of fetch() and also .then() after that. Shouldn't either of them do?
The error this.state.matchInfo.map is not a function would occur only when this.state.matchInfo is not an array but you have initialized it to be one, so at any point of time matchInfo gets modified it must be becoming non-array like an object or something which doesn't have a native .map().
Have you checked response coming from API? I hope this helps.
this.setState({ matchInfo: body });
mapData = () => {
this.state.matchInfo.map((item , index)=>{
return(
<View>
<MatchDetailBox />
<View>
{item}
</View>
</View>
)
})
}
render() {
return {this.mapData()}
}
I am creating react-native app using fetch method to get the data from API but when I am build the app(remove and install new app) that time it is calling API called but on 2nd time it is not.
I have also uses
componentDidMount, componentWillMount
but not work for me. following is my code:
export default test extends Component{
_isMounted = false;
constructor(props){
super(props);
this.state = {
showList:[]
}
}
componentDidMount() {
let currentComponent = this;
currentComponent._isMounted = true;
fetch(API_URL, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
}
}).then((response) => { return response.json()})
.then((responseJson) => {
console.warn("responseJson: ", responseJson);
if(currentComponent._isMounted){
currentComponent.setState({showList: responseJson.data});
}
})
.catch((error) => {
console.error(error);
});
}
componentWillUnmount(){
this._isMounted = false
}
}
I have add full code here. this is only called on first time, after that it will get only from cache(I think).Please help me.
Thanks
I'd look into the onEnter hook on your scene using react-native-router-flux.
Something like this should work:
class Test extends Component {
static onEnter() {
fetch(API_URL, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
}
}).then((response) => { return response.json()})
.then((responseJson) => {
console.warn("responseJson: ", responseJson)
if (currentComponent._isMounted) {
currentComponent.setState({ showList: responseJson.data })
}
})
.catch((error) => {
console.error(error)
})
}
}
(if you need to access this in the method, here is an idea)