ReactJS: wait until state is filled before making next call - reactjs

I have quite a big function that retrieves a bunch of information about Spotify playlists. Because the data is paginated I have a to make a couple of calls and append data to the state recursively. After that's done, I want to pass the state along with a POST request to another endpoint, to make some calculations. The returned values are then stored in state as well.
const fetchPlaylist = (playlistId) => {
showLoading()
setTitles([])
setArtists([])
setFeatures([])
setTSNEfeatures([])
setIds([])
setLabels([])
const getPlaylistDataRecursively = (url) => {
return fetch('/spotify/get-track-ids', {headers: {
'url': url
}})
.then(response => response.json())
.then(data => {
console.log(data)
setTitles(titles => ([...titles, ...data.title]))
setArtists(artists => ([...artists, ...data.artist]))
setFeatures(features => ([...features, ...data.features]))
setIds(ids => ([...ids, ...data.track_ids]))
if (data.next_url) {
const next_url = data.next_url.replace('https://api.spotify.com/v1', '')
return getPlaylistDataRecursively(next_url)
} else {
return fetch('/spotify/get-dimension-reduction', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(features)
})
.then(response => response.json())
.then(data => {
setTSNEfeatures(data)
})
}
})
}
return getPlaylistDataRecursively(`/playlists/${playlistId}/tracks/?offset=0&limit=100`)
.then(() => {
hideLoading()
});
}
The problem is that fetch('/spotify/get-dimension-reduction' ... ) is ran before getPlaylistDataRecursively is done filling the features state. How can I tackle this issue?

Related

ReactJS: post request with data through fetch

In my app component, I have state features that contains an array(1500) of arrays(9). I want to send the state (or large array) to my backend so I can run my model and return labels with the following function:
const getLabels = (model) => {
fetch('/spotify/get-labels', {headers: {
'model': model,
'features': features
}})
.then(response => response.json())
.then(data => setLabels(data))
}
However, the response has status 431. This was kinda expected, but I'm not sure how to transmit the data to my backend efficiently. Maybe convert it to json and then put in the headers of my request?
You can try something like this with fetch:
fetch('/spotify/get-labels', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ model, features }),
})
.then((response) => response.json())
.then((data) => {
// Boom!
})
.catch((error) => {
// An error happened!
});
or with axios
axios
.post('/spotify/get-labels', { model, features })
.then((data) => {
// Boom!
})
.catch((error) => {
// An error happened!
});
As far as I'm understanding your concern, I guess passing the 'model': model,'features': features in body should work.
Or using Axios, you can make the request. It exactly like Axios but far better
axios({
url: '/spotify/get-labels',
method: "post",
data: {
'model': model,
'features': features
},
})
.then((response) => response.json())
.then(data => setLabels(data))
.catch((error) => {
console.log("error : ", JSON.parse(error));
});

Fetch request is not updating the state

I have an react application connected to a database. Currently the app takes the database when it mounts and uses that to populate the state. The apps allows someone to post to the database. So far that works.
The issue is that I want the new posted content to be seen by the user. As it is the content only populates after I reload the page. I tried to repeat the coding in the componentDidMount() in a function that runs after the POST request, but for someone reason that is not working.
class App extends Component {
state = {
notes: [],
folders: [],
//noteID: 0,
//folderID: 0
};
componentDidMount() {
Promise.all([
fetch(`${config.API_ENDPOINT}/notes`),
fetch(`${config.API_ENDPOINT}/folders`)
])
.then(([notesRes, foldersRes]) => {
if (!notesRes.ok)
return notesRes.json().then(e => Promise.reject(e))
if (!foldersRes.ok)
return foldersRes.json().then(e => Promise.reject(e))
return Promise.all([
notesRes.json(),
foldersRes.json(),
])
})
.then(([notes, folders]) => {
this.setState({ notes, folders })
})
.catch(error => {
console.error({ error })
})
}
pageReload = () =>{
//console.log('pageReload ran');
Promise.all([
fetch(`${config.API_ENDPOINT}/notes`),
fetch(`${config.API_ENDPOINT}/folders`)
])
.then(([notesRes, foldersRes]) => {
if (!notesRes.ok)
return notesRes.json().then(e => Promise.reject(e))
if (!foldersRes.ok)
return foldersRes.json().then(e => Promise.reject(e))
return Promise.all([
notesRes.json(),
foldersRes.json(),
])
})
.then(([notes, folders]) => {
this.setState({ notes, folders })
})
.catch(error => {
console.error({ error })
})
}
folderSubmit = (f) => {
//console.log("folderSubmit ran " + f);
const newFolder = { "name" : f };
const postfolder = {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(newFolder)
};
fetch(`${config.API_ENDPOINT}/folders`, postfolder).then(this.pageReload())
}
It looks like you are not setting your state after post. see below where you need to set your state.
folderSubmit = (f) => {
//console.log("folderSubmit ran " + f);
const newFolder = { "name" : f };
const postfolder = {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(newFolder)
};
fetch(`${config.API_ENDPOINT}/folders`, postfolder)
.then(response => response.json())
.then(data => this.setState(data));
}

React: res.json() data is undefined

I'm having issues with getting data from my fetch API. It was working previously when I had "test" inside of a class. Now that it's inside of a function, I get "undefined" when I try to console.log(data). (Note, the API call is working on the server. console.log(res.json()) returns a data. I'm LOST.
const test = () => {
fetch('/api/test/', {
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
//make sure to serialize your JSON body
body: JSON.stringify({zip: val})
})
.then(res => { res.json()}) //THIS RETURNS OK
.then(data => {console.log({data})}) //THIS IS WHERE I HAVE PROBLEMS
}
EDIT:
I also tried
.then(data=> {console.log(data)})
and
.then(data => {console.log([data])})
is there something I'm missing?
Arrow_functions
You should return res.json() to work successfully;
.then(res => { return res.json()})
or
.then(res => res.json())

Unable to get response using fetch in React

I am trying to call 3rd party API, to fetch some data. I am getting the response in Postman, but not getting expected response when I execute my code.
I tried in 2 ways. Both ways I am getting "Promise pending".What could be the reason??
//request.js
Method 1
export const callSearchGiftsAPI = inputs => dispatch => {
dispatch(searchGifts());
let url = new URL(GIFT_SEARCH_API_URL),
params = {
apiKey: GIFT_SEARCH_API_KEY,
query: inputs.item,
country: 'us',
itemsPerPage: 3
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
return new Promise((resolve, reject) => {
setTimeout(() => resolve(
fetch(url, {
method: 'GET',
// mode: 'no-cors',
headers: {
'Content-Type': 'application/json',
Authorization: `secret ${SECRET}`
}
})
.then(res => {
if (!res.ok) {
return Promise.reject(res.statusText);
}
console.log("hi", res.json());
return res.json();
})
.then(gifts => dispatch(searchGiftsSuccess(gifts)))
.catch(err => dispatch(searchGiftsError(err)))), 500)
});
}
Method 2:
export const callSearchGiftsAPI = inputs => dispatch => {
dispatch(searchGifts());
let url = new URL(GIFT_SEARCH_API_URL),
params = {
apiKey: GIFT_SEARCH_API_KEY,
query: inputs.item,
country: 'us',
itemsPerPage: 3
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
fetch(url, {
method: 'GET',
// mode: 'no-cors',
headers: {
'Content-Type': 'application/json',
Authorization: `secret ${SECRET}`
}
})
.then(res => {
if (!res.ok) {
return Promise.reject(res.statusText);
}
console.log('result', res.json());
return res.json();
})
.then(gifts => dispatch(searchGiftsSuccess(gifts)))
.catch(err => dispatch(searchGiftsError(err)));
};
//form.js
class Form extend React.Component{
onSubmit(values) {
const inputs = Object.assign({}, values);
return this.props.dispatch(callSearchGiftsAPI(inputs));
}
//Remaining code
}
Also please note that I have installed CORS plugin in Chrome, to allow the request.If I disable it and add mode:'no-cors' I am getting as 401 unauthorized.What else am I supposed to do?
What happens is that you are creating a new Promise and returning it, but you are not waiting for it to resolve. You can either use then of the new async/await syntax to get the correct result :
onSubmit = async values => {
const inputs = Object.assign({}, values);
return await this.props.dispatch(callSearchGiftsAPI(inputs));
}
The code above will work with your first method.
Since your second method does not return anything, you will never get your result, you need to return your fetch's result and apply the code I gave above :
return fetch(url, {
This worked.
I was trying to put console.log in the wrong place and hence was not able to see the response properly.
export const callSearchGiftsAPI = inputs => dispatch => {
dispatch(searchGifts());
let url = new URL(GIFT_SEARCH_API_URL),
params = {
apiKey: GIFT_SEARCH_API_KEY,
query: inputs.item,
country: 'us',
itemsPerPage: 3
};
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
console.log(url);
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `secret ${SECRET}`
}
})
.then(res => {
console.log('result');
return res.json();
})
.then(response => {
console.log(response); // changed
dispatch(searchGiftsSuccess(response.items));
})
.catch(err => dispatch(searchGiftsError(err)));

React Native refreshing data

I'm trying to refresh some data when users re-vistis the screen. The way im using other places and it works. but can't figure out why this won't fly on this screen?
componentDidMount = () => {
this.props.navigation.addListener('didFocus', this.handleDidFocus)
}
async handleDidFocus() {
...
}
This is how I load data the first time and want to load it again when users revisits.
componentWillMount() {
this.getGroupAccepted();
}
async getGroupAccepted() {
if (this.state.token == null) {
var token = await AsyncStorage.getItem("token");
this.setState({ "token": token });
}
fetch('https://.../api/group/getActive', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
token: this.state.token
})
})
.then(response => response.json())
.then((data) => {
this.setState({
groups_accepted: data.groups_active,
loading: false,
});
})
.catch((error) => {
console.error(error);
});
}
This is what worked. Now when a user revisits the screen it loads the data once again.
componentDidMount = () => {
this.props.navigation.addListener('didFocus', this._handleDataChange)
}
_handleDataChange = () => {
this.getGroupAccepted();
}

Resources