Call two fetch function with setState in between - reactjs

I am trying to call two fetch APIs to store the information.
After first API call to cloudinary I get the URL back, which I want to store in state before hitting second API to store info in database. I am getting setAddOnData undefined error. While I try to make second API call , code functions properly for single API
const onSubmit = e => {
e.preventDefault();
console.log(fileInputRef.current.files[0]);
const myNewCroppedFile = fileInputRef.current.files[0];
console.log(myNewCroppedFile);
const formData = new FormData();
formData.append('file', myNewCroppedFile);
formData.append('upload_preset', 'xprl6rwq');
const options = {
method: 'POST',
body: formData
};
const addOnBody = JSON.stringify({ itemName, itemIconURL, itemPrice });
const config = {
headers: {
'Content-Type': 'application/JSON'
}
};
const option2 = {
method: 'POST',
body: addOnBody
};
return fetch(
'https://api.Cloudinary.com/v1_1/antilibrary/image/upload',
options
)
.then(res => res.json())
.then(res =>
setAddOnData({
...addOnData,
itemIconURL: res.secure_url
})
)
.then(fetch(`/api/v1/addOn`, option2, config))
.then(res => res.json());
};
const [addOnData, setAddOnData] = useState({
addOnCategory: '',
itemName: '',
itemPrice: '',
itemIconURL: '',
itemIconFileName: '',
step: 1
});

setState calls are asynchronous. When you run your second fetch call, the setAddOnData hasn't necessarily updated the addonData variable yet. You'd be best off moving the second fetch call to a useEffect which is dependent on the data returned from your first fetch call.
const addOnBody = JSON.stringify({ itemName, itemIconURL, itemPrice });
const config = {
headers: {
'Content-Type': 'application/JSON'
}
};
const option2 = {
method: 'POST',
body: addOnBody
};
const onSubmit = e => {
...
return fetch(
'https://api.Cloudinary.com/v1_1/antilibrary/image/upload',
options
)
.then(res => res.json())
.then(res =>
setAddOnData({
...addOnData,
itemIconURL: res.secure_url
})
)
};
useEffect( () => {
fetch(`/api/v1/addOn`, option2, config)
.then(res => res.json());
},[addOnData.itemIconURL])

Related

I want to decrease my stock amount by the delivery button in MongoDb

How do i decrease stock in my react app by a delivery button which is connected in MongoDB
If you click on the Delivered button, you will reduce the quantity one by one, then you will send that value to the backend and update it in the database.
Increase in the same way.
as like...
const stockQuantity = parseInt(products?.quantity)
const newStockQuantity = stockQuantity - 1;
then
fetch(url, {
method: 'PUT', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(
{
quantity: newStockQuantity,
}
),
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
toast('Your Product Deliver successfully')
setIsReload(!reload)
})
const delevary = e => {
const quantity = product?.quantity
const updateItem = {quantity}
const url = `http://localhost:7000//${id}`;
fetch(url,{
method : 'PUT',
headers : {
'content-type' : 'application/json'
},
body : JSON.stringify(updateItem)
})
.then(res => res.json())
.then (result =>{
console.log(result)
setIsreload(!isReload)
// setItems(result);
})
};

How can I update quantity of the product in UI, immediately at the time of updating the database?

const [product, setProduct] = useState({});
useEffect(() => {
const url = `http://localhost:5000/product/${id}`;
fetch(url)
.then(res => res.json())
.then(data => setProduct(data))
}, [id]);
const handleDeliveredBtn = id => {
const newQuantity = parseInt(quantity) - 1;
const updatedQuantity = { newQuantity };
const url = `http://localhost:5000/product/${id}`;
fetch(url, {
method: 'PUT',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(updatedQuantity)
})
.then(res => res.json())
.then(data => {
toast('Product delivered successfully.');
})
};
I want to show the updatedQuantity in my UI. Quantity is updated at database. But, without reloading the page, I can't see any changes that happen in my UI.
You need to use setProduct to cause a render. React components only render whenever there is a change in the state or props, which in your case is invoked by the setProduct.
const [product, setProduct] = useState({});
useEffect(() => {
const url = `http://localhost:5000/product/${id}`;
fetch(url)
.then(res => res.json())
.then(data => setProduct(data))
}, [id]);
const handleDeliveredBtn = id => {
const newQuantity = parseInt(quantity) - 1;
const updatedQuantity = { newQuantity };
const url = `http://localhost:5000/product/${id}`;
fetch(url, {
method: 'PUT',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(updatedQuantity)
})
.then(res => res.json())
.then(data => {
toast('Product delivered successfully.');
setProduct(data) // add setProduct
})
};
You might want to make a shallow copy instead for performance / unnessecary renders but for the sake of example I just added setProduct(data).
You need one more useState hook to display updated value in your UI. checkout below code:
const [product, setProduct] = useState({});
const [updatedQuantity, setUpdatedQuantity] = useState({});
useEffect(() => {
const url = `http://localhost:5000/product/${id}`;
fetch(url)
.then(res => res.json())
.then(data => setProduct(data))
}, [id]);
const handleDeliveredBtn = id => {
const newQuantity = parseInt(quantity) - 1;
setUpdatedQuantity(newQuantity);
const url = `http://localhost:5000/product/${id}`;
fetch(url, {
method: 'PUT',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(updatedQuantity)
})
.then(res => res.json())
.then(data => {
toast('Product delivered successfully.');
})
};
now you can use updatedQuantity as a current data in your UI.

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?

Setting a state in fetch call gives me undefined?

Hi im trying to set a state in my fetch call, When I try to access the state it returns undefined. Im not sure why it does this can someone help?
var [articlearray, setArticle]= React.useState([]);
var options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({headline: props.headline})
};
fet(options)
function fet(options){
fetch('/headlines', options).then(response => response.json()).then(data =>{
var newsData = data.newsArray
setArticle(newsData)
})
}
console.log(articlearray[0]);
You could use useEffect to load all of your data from an API endpoint. The emtpy array [] on the useEffect means that it will run once, on the beginning of the lifecycle.
var [articlearray, setArticle] = React.useState([]);
const fetchData = async () => {
var options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
headline: props.headline
})
};
fetch('/headlines', options).then(response => response.json()).then(data => {
var newsData = data.newsArray;
setArticle(newsData);
console.log(articlearray[0]);
})
}
useEffect(() => {
fetchData();
}, []);

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