How to retrieve data from promise object in React JS - reactjs

I am trying to get data from an API. But the fetch result is returned as promise object. I want to return the contents from this promise to invoke react action.
let loginData = fetch(loginURL, { method : 'POST', headers : headerParams,
body: bodyParams })
.then((response) => response.json())
.then(data => {
return data['retrieve-agent'];
});
console.log('loginData ===>', loginData.agent);
return {
type: 'GET_AGENT_DETAILS',
payload: loginData
}

Make use of async-await to get the result without using a promise or else you would need to resolve the promise from the function
async fetchFunction() {
let loginData = await fetch(loginURL, { method : 'POST', headers : headerParams,
body: bodyParams })
.then((response) => response.json())
.then(data => {
return data['retrieve-agent'];
});
console.log('loginData ===>', loginData.agent);
return {
type: 'GET_AGENT_DETAILS',
payload: loginData
}
}

Related

How can I include response data to axios response?

I try to work with Axios interceptors. The problem I'm facing is that I can't show the response I got from the API with Axios or even if it does, it shows constant data.
axios.defaults.baseURL = 'https://localhost:5001/api/';
axios.defaults.withCredentials = true;
const responseBody = res => res.data;
axios.interceptors.response.use(async response => {
const pagination = response.headers["x-pagination"];
if (pagination) {
const parsed = JSON.parse(pagination);
let metaData = {
currentPage: parsed.currentPage,
pageSize: parsed.pageSize,
totalPages: parsed.totalPages,
totalCount: parsed.totalCount
};
response.data = {
metaData,
data: response.data //I want to change this data
// For example there is an endpoint named getAll and it returns all object
// Also there is a get endpoint and it returns a single object
// But the problem is axios always return getAll endpoint's data.
};
return response;
}
}, error => {
return Promise.reject(error);
});
This is my request object
const requests = {
get: (url, params) => axios.get(url, {params}).then(responseBody),
post: (url, data) => axios.post(url, data).then(responseBody),
put: (url, data) => axios.put(url, data).then(responseBody),
delete: (url) => axios.delete(url).then(responseBody),
postForm: (url, data) => axios.post(url, data, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(responseBody),
putForm: (url, data) => axios.put(url, data, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(responseBody)
};
and this is my API endpoints
const Endpoints = {
getAll: () => requests.get('Endpoint'),
get: (id) => requests.get(`Endpoint/${id}`),
create: (data) => requests.postForm('Endpoint', data),
update: (id, data) => requests.putForm(`Endpoint/${id}`, data),
delete: (id) => requests.delete(`Endpoint/${id}`),
}
What am I missing? Also, I use Redux Slice. If you want I can also send the redux code I write.
axios.interceptors.response.use(async response => {
const pagination = response.headers["x-pagination"];
if (pagination) {
const parsed = JSON.parse(pagination);
let metaData = {
currentPage: parsed.currentPage,
pageSize: parsed.pageSize,
totalPages: parsed.totalPages,
totalCount: parsed.totalCount
};
response.data = {
metaData,
data: response.data
};
return response;
}
return response; // problem solved after this
}, error => {
return Promise.reject(error);
});
The problem is I forget to return the response so that's why I always get the same data.

ReactJS: wait until state is filled before making next call

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?

call function synchronously in reactjs

I want to call function only after previous function gets executed. I tried with promises but its not working,I also tried with async await but the last function is getting executed.After execution of first function its state value i want to pass to next function and so on.Please help me in this.Thanks in advance.
handleAllFunctionsOnClickPayLater() {
let promise = Promise.resolve();
promise
.then(() => this.handleGuestLogin())
.then(() => setTimeout(this.handleAddress(),1000))
.then(() => setTimeout(this.handlePayLater(),2000))
}
handleGuestLogin() {
const UserDetails = {
name: this.state.name,
email: this.state.email,
mobile: this.state.number
}
fetch(api,{
method : 'POST',
body: JSON.stringify(UserDetails)
})
.then(res => res.json())
.then(data => {
return this.setState({
cid: data.Data.cid
},() => {console.log(this.state.cid)})
})
}
handleAddress() {
var address_details = {
cid:this.state.cid
...other details
}
fetch(api,{
method : 'POST',
body: JSON.stringify(address_details)
})
.then(res => res.json())
.then(data => {
console.log("address added in db customer_address",data);
return this.setState({
address_id: data.address_id,
})
}
handlePayLater = () => {
var bookingDetails = {
cid: this.state.cid,
address_id: this.state.address_id
}
fetch(api,{
method : 'POST',
body : JSON.stringify(bookingDetails)
})
.then(res => res.json())
.then(data => {
return this.setState({bookingId:data.booking_id});
}
Assuming handleAddress, handleGuestLogin and handlePayLater return promises, you can use an async/await function
synchronousPromises = async () => {
try {
const handleGuestLoginResult = await this.handleGuestLogin();
const handleAddressResult = await this.handleAddress();
const handlePayLaterResult = await this.handlePayLater();
} catch (error)
{
return reject(error); //will cause .catch to fire
}
return resolve([
handleGuestLoginResult,
handleAddressResult,
handlePayLaterResult
]); //will cause .then to fire
}
since synchronousPromises is an async function, it itself returns a promise. to use it, you can call it as
callSyncronousPromises = () => {
synchronousPromises()
.then(success => {
//handle success
})
.catch(error => {
//handle error
}
}

Rewrite fetch call to oboe for json streams with Typescript

I have this fetch call:
api<T>(url: string, headers: Request): Promise<T> {
return fetch(url, headers)
.then(response => {
if (!response.ok) {
throw new Error(response.statusText);
}
return response.json().then(data => data as T);
})
.catch((error: Error) => {
throw error;
});
}
componentDidMount(){
this.api<Array<Response>>(url, requestData)
.then(data => {
this.setState({
jobs: data
});
})
.catch(error => {
console.error(error);
});
}
But the response that I get is a stream+json so I get invalid json at .json().
I saw that there is a library that can help me: http://oboejs.com/examples
But I'm having issues using oboe and typescript (beginner) (using https://www.npmjs.com/package/#types/oboe).
I tried:
api<T>(headers: Request): Oboe<T> {
return oboe(headers)
.done(function(response) {
return response;
})
.fail(function(error: Error) {
throw error;
});
}
componentDidMount(){
this.api<Array<Response>>(requestData)
.done(data => {
this.setState({
jobs: data
});
})
.fail(error => {
console.error(error);
});
}
But there are obvious errors as I don't know what type oboe should return so I get an error Oboe is not generic.
The error means that the Oboe class/type is not generic. Like Number of String for example
From Oboe's docs it seems that oboe(param).done() takes a callback
You can transform that call into a Promise and do the rest the same way you used to do
Replacing the callback logic with a Promise
api<T>(headers: Request): Promise<T> {
return new Promise((resolve, reject) => {
oboe(headers)
.done(data => resolve(data))
.fail(err => reject(err));
});
}
Calling it (the way you did with Promise/fetch)
componentDidMount(){
this.api<Array<Response>>(url, requestData)
.then(data => {
this.setState({
jobs: data
});
})
.catch(error => {
console.error(error);
});
}

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

Resources