Using the state hook to count inside of promises - reactjs

I am back with a newbie question, eventually i have built a function too complex with my promises, but maybe someone has some insight in why the setSiteAdded/Updated and setArticlesAdded/Updated functions are not working in the correct way for me here. I want to count up, all directly saved and updated elements of the fetched data from my API.
I am using typeORM locally on my ios device with sqlite.
Here is my code:
const saveToDB = (type, element) => {
return new Promise(async (resolve, reject) => {
if (type === 'site') {
let site = new Site();
site.created = element.CREATED;
site.sitenum = element.SITENUM;
site.title = element.TITLE;
site.updated = element.UPDATED;
let siteRepository = getRepository(Site);
siteRepository.findOne({ where: { sitenum: site.sitenum } })
.then((foundSite) => {
site.id = foundSite.id;
if (foundSite.updated !== site.updated) {
siteRepository.update(foundSite.id, site)
.then((savedSite) => {
console.log("Site has been updated!", savedSite);
setSitesUpdated(sitesUpdated + 1);
resolve(savedSite);
}).catch((error) => {
console.log("Error: ", error);
reject();
});
} else {
resolve();
}
})
.catch(() => {
siteRepository.save(site)
.then((savedSite) => {
console.log("Site has been saved!", savedSite);
setSitesAdded(sitesAdded + 1);
resolve(savedSite);
})
.catch((error) => {
console.log("Error: ", error);
reject();
});
});
} else if (type === 'article') {
let article = new Article();
article.created = element.CREATED;
article.updated = element.UPDATED;
article.artnum = element.ARTNUM;
article.ean = element.EAN;
article.title1 = element.TITLE1;
article.title2 = element.TITLE2;
article.unit = element.UNIT;
article.price = element.PRICE;
article.quantity = element.QUANTITY;
let articleRepository = getRepository(Article);
articleRepository.findOne({ where: { artnum: article.artnum } })
.then((foundArticle) => {
article.id = foundArticle.id;
if (foundArticle.updated !== article.updated) {
articleRepository.update(foundArticle.id, article)
.then((savedArticle) => {
console.log("Article has been updated!", savedArticle);
setArticlesUpdated(articlesUpdated + 1);
resolve(savedArticle);
})
.catch((error) => {
console.log("Error: ", error);
reject();
});
} else {
resolve();
}
})
.catch(() => {
articleRepository.save(article)
.then((savedArticle) => {
console.log("Article has been saved!", savedArticle);
setArticlesAdded(articlesAdded + 1);
resolve(savedArticle);
})
.catch((error) => {
console.log("Error: ", error);
reject();
});
});
}
})
}
const fetchDataFromServer = () => {
return new Promise(async (resolve, reject) => {
setLoading(true);
Promise.all([
new Promise(async (resolve, reject) => {
try {
let counter = 0;
let sites = await fetch(
host + 'sites', { method: 'GET', headers: { token: token } }
)
let sitesJson = await sites.json();
Promise.all(sitesJson.data.map(async (element) => {
counter++;
return saveToDB('site', element)
}))
.then(() => {
setSitesAdded(counter);
resolve();
})
.catch(() => reject());
} catch (error) {
console.error(error);
}
}),
new Promise(async (resolve, reject) => {
try {
let articles = await fetch(
host + 'articles', { method: 'GET', headers: { token: token } }
)
let articlesJson = await articles.json();
Promise.all(articlesJson.data.map(async (element) => {
return saveToDB('article', element)
}))
.then(() => resolve())
.catch(() => reject());
} catch (error) {
console.error(error);
}
})
])
.then(() => resolve())
.catch(() => reject())
})
}

Related

Duplicate data saving on MongoDB

Hello I'm having a problem on my function save on my react project.
onSubmit={async (data, { setSubmitting, resetForm }) => {
for (var i = 0; i < selectedImageFiles.length; i++) {
const urlLink = await generateUploadUrl(selectedImageFiles[i].type);
const to_base64 = (file) =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = (error) => reject(error);
});
let blob = await to_base64(selectedImageFiles[i]);
let binary = atob(blob.split(",")[1]);
let array = [];
for (var x = 0; x < binary.length; x++) {
array.push(binary.charCodeAt(x));
}
let blobData = new Blob([new Uint8Array(array)], {
type: selectedImageFiles[i].type,
});
const uploadImageLink = await uploadImage(urlLink, blobData);
const newUploadImageLink = uploadImageLink.url.split("?")[0];
let productData = {
...data,
shopId: userShop._id,
images: selectedImageFiles,
category: collectCategoryId()[0],
};
addProduct(productData, userShop._id, newUploadImageLink).then(
(response) => {
if (response.status === 200) {
response.json().then((result) => {
setSubmitting(false); });
} else {
response.json().then((result) => {
setSubmitting(false);
});
}
}
);
}
}}
>
When I upload 2 files it also create 2 files on my database with same image link on both.
What I want is to create 1 data on database then the images.url must be different link from what I uploaded.
data number 1 that is inserted
{
"_id": {
"$oid": "62395b2faff15038acab7d0e"
},
"images": [{
"url": "https://devs.s3.ap-southeast-1.amazonaws.com/1647926063980.png",
}, {
"url": "https://devs.s3.ap-southeast-1.amazonaws.com/1647926063980.png",
}],
}
data number 2 that is inserted
{
"_id": {
"$oid": "62395b2faff15038acab7d0e"
},
"images": [{
"url": "https://devs.s3.ap-southeast-1.amazonaws.com/1647926063313.jpg",
}, {
"url": "https://devs.s3.ap-southeast-1.amazonaws.com/1647926063313.jpg",
}],
}
this is my addProduct
export const addProduct = async (productData, shopId, url) => {
const ls = new SecureLS({ encodingType: "aes" });
const token = ls.get("token");
const formdata = new FormData();
// console.log(productData.name);
for (let index = 0; index < productData.images.length; index++) {
formdata.append("file", productData.images[index]);
}
formdata.append("category", productData.category);
formdata.append("name", productData.name);
formdata.append("quantity", productData.quantity);
formdata.append("price", productData.price);
formdata.append("description", productData.description);
formdata.append("ingredients", productData.ingredients);
formdata.append("url", url);
return await fetch(`${API}/product/${shopId}`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
body: formdata,
})
.then((response) => {
return response;
})
.catch((err) => {
//console.log(err)
return err;
});
};
maybe something like this you need to be re debug and check addProduct last parameter :
onSubmit = async (data, { setSubmitting, resetForm }) => {
let filesUrls = [];
for (var i = 0; i < selectedImageFiles.length; i++) {
const urlLink = await generateUploadUrl(selectedImageFiles[i].type);
const to_base64 = (file) =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = (error) => reject(error);
});
let blob = await to_base64(selectedImageFiles[i]);
let binary = atob(blob.split(",")[1]);
let array = [];
for (var x = 0; x < binary.length; x++) {
array.push(binary.charCodeAt(x));
}
let blobData = new Blob([new Uint8Array(array)], {
type: selectedImageFiles[i].type,
});
const uploadImageLink = await uploadImage(urlLink, blobData);
const newUploadImageLink = uploadImageLink.url.split("?")[0];
filesUrls.push(newUploadImageLink);
}
let productData = {
...data,
shopId: userShop._id,
images: filesUrls,
category: collectCategoryId()[0],
};
addProduct(productData, userShop._id).then(
(response) => {
if (response.status === 200) {
response.json().then((result) => {
setSubmitting(false);
});
} else {
response.json().then((result) => {
setSubmitting(false);
});
}
});
}

React Hook , setvariable and print in same useeffect

I want to set name,room variable after axios calling and before socket.join. But SetName() is not working properly, and socket.join() is not receiving new value of Name, Room.
Name and Room value of set after socket.join() is completed, but I wanted is to set Name and Room value before socket.join()
useEffect(() => {
(async () => {
const response = await axios({
method: "get",
url: "https://localhost:5000/",
mode: "cors",
withCredentials: true,
});
const data = await response.data;
await condition_check();
await soc();
function condition_check() {
return new Promise(async (resolve) => {
if (location.state === undefined) {
SetConnected(true);
SetValid(false);
}
if (data.status === "ok" && location.state !== undefined) {
SetName(location.state.Name, () => {
console.log(name);
});
SetRoom(location.state.Room);
SetUserId(location.state.UserId);
SetValid(true);
resolve(console.log("1", name, room));
SetConnected(true);
SetSetup(true);
}
});
}
function soc() {
return new Promise((resolve) => {
if (setup === true) {
socket = socketIOClient.connect(ENDPOINT);
socket.emit(
"Join",
{ Name: name, Room: room, UserId: userid },
(err) => {
if (err) {
alert(err);
}
}
);
console.log("2", name, room);
socket.on("message", ({ Name, Room, message, currenttime }) => {
setMessages((messages) => [...messages, message]);
setSenders((senders) => [...senders, Name]);
setTime((time) => [...time, currenttime]);
resolve(console.log(currenttime));
});
}
});
}
})();
// because `SetRoom` `SetName` is async
useEffect(() => {
(async () => {
const response = await axios({
method: "get",
url: "https://localhost:5000/",
mode: "cors",
withCredentials: true,
});
const data = await response.data;
let NAME;
let ROOM;
await condition_check();
await soc();
function condition_check() {
return new Promise(async (resolve) => {
if (location.state === undefined) {
SetConnected(true);
SetValid(false);
}
if (data.status === "ok" && location.state !== undefined) {
...
NAME = location.state.Name
ROOM = location.state.Room
...
}
});
}
function soc() {
// use local variable `ROOM` and `NAME`
return new Promise((resolve) => {
...
});
}
})();

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

Export problems in ReactJS

Hello it's been 2 weeks since I am learning React and Redux I wanted to know that from my ActionCreators.js file i exported the const postFeedback and imported it in my MainComponent.js But I am getting this error
./src/Components/MainComponent.js
Attempted import error: 'postFeedback' is not exported from '../redux/ActionCreators'.
***This is my ActionCreators.js File
import * as ActionTypes from './ActionTypes';
import {baseUrl} from '../shared/baseUrl';
export const addComment = (comment) => ({
type: ActionTypes.ADD_COMMENT,
payload: comment
});
//////
export const postComment = (dishId, rating, author, comment) => (dispatch) => {
const newComment = {
dishId: dishId,
rating: rating,
author: author,
comment: comment
};
newComment.date = new Date().toISOString();
return fetch(baseUrl + 'comments', {
method: "POST",
body: JSON.stringify(newComment),
headers: {
"Content-Type": "application/json"
},
credentials: "same-origin"
})
.then(response => {
if (response.ok) {
return response;
} else {
var error = new Error('Error ' + response.status + ': ' + response.statusText);
error.response = response;
throw error;
}
},
error => {
throw error;
})
.then(response => response.json())
.then(response => dispatch(addComment(response)))
.catch(error => { console.log('post comments', error.message); alert('Your comment could not be posted\nError: '+error.message); });
};
///FEEDBACK
export const postFeedback = (feedback) => (dispatch) => {
const newFeedback = Object.assign({ date: new Date().toISOString() }, feedback);
return fetch(baseUrl + 'feedback', {
method: 'POST',
body: JSON.stringify(newFeedback),
headers: {
'Content-Type': 'application/json'
},
credentials: 'same-origin'
})
.then(response => {
if (response.ok) {
return response;
} else {
var error = new Error('Error ' + response.status + ': ' + response.statusText);
error.response = response;
throw error;
}
},
error => {
var errorMessage = new Error(error.errorMessage);
throw errorMessage;
}
)
.then(response => response.json())
.then(response => dispatch(addComment(response)))
.catch(error => {
console.log('Post feedback: ' + error.message);
alert('Feedback could not be posted:\n' + error.message)
})
};
//////
export const fetchDishes = () => (dispatch) => {
dispatch(dishesLoading(true));
return fetch(baseUrl + 'dishes')
.then(response => {
if (response.ok) {
return response;
} else {
var error = new Error('Error ' + response.status + ': ' + response.statusText);
error.response = response;
throw error;
}
},
error => {
var errmess = new Error(error.message);
throw errmess;
})
.then(response => response.json())
.then(dishes => dispatch(addDishes(dishes)))
.catch(error => dispatch(dishesFailed(error.message)));
}
export const fetchComments = () => (dispatch) => {
return fetch(baseUrl + 'comments')
.then(response => {
if (response.ok) {
return response;
} else {
var error = new Error('Error ' + response.status + ': ' + response.statusText);
error.response = response;
throw error;
}
},
error => {
var errmess = new Error(error.message);
throw errmess;
})
.then(response => response.json())
.then(comments => dispatch(addComments(comments)))
.catch(error => dispatch(commentsFailed(error.message)));
};
export const fetchPromos = () => (dispatch) => {
dispatch(promosLoading());
return fetch(baseUrl + 'promotions')
.then(response => {
if (response.ok) {
return response;
} else {
var error = new Error('Error ' + response.status + ': ' + response.statusText);
error.response = response;
throw error;
}
},
error => {
var errmess = new Error(error.message);
throw errmess;
})
.then(response => response.json())
.then(promos => dispatch(addPromos(promos)))
.catch(error => dispatch(promosFailed(error.message)));
}
///***Assignment4 where we used all the three actions in this thunk to make effective use of them and also to make the fetch available
export const fetchLeaders = () => (dispatch) => {
dispatch(leadersLoading());
return fetch(baseUrl + 'leaders')
.then(response => {
if (response.ok) {
return response;
} else {
var error = new Error('Error ' + response.status + ': ' + response.statusText);
error.response = response;
throw error;
}
},
error => {
var errmess = new Error(error.message);
throw errmess;
})
.then(response => response.json())
.then(promos => dispatch(addLeaders(promos)))
.catch(error => dispatch(leadersFailed(error.message)));
}
export const commentsFailed = (errmess) => ({
type: ActionTypes.COMMENTS_FAILED,
payload: errmess
});
export const addComments = (comments) => ({
type: ActionTypes.ADD_COMMENTS,
payload: comments
});
export const dishesFailed = (errmess) => ({
type: ActionTypes.DISHES_FAILED,
payload: errmess
});
export const promosLoading = () => ({
type: ActionTypes.PROMOS_LOADING
});
export const promosFailed = (errmess) => ({
type: ActionTypes.PROMOS_FAILED,
payload: errmess
});
export const addPromos = (promos) => ({
type: ActionTypes.ADD_PROMOS,
payload: promos
});
export const addDishes = (dishes) => ({
type: ActionTypes.ADD_DISHES,
payload: dishes
});
export const dishesLoading = () => ({
type:ActionTypes.DISHES_LOADING
});
/////***Assignement4
//basically we created the actions here now to make them be used using thunk
export const addLeaders = (leaders) => ({
type: ActionTypes.ADD_LEADERS,
payload: leaders
});
///
export const leadersLoading = () => ({
type: ActionTypes.LEADERS_LOADING,
});
export const leadersFailed = (errmess) => ({
type: ActionTypes.LEADERS_FAILED,
payload: errmess
});
//ADDED THREE NEW ACTIONS NOW TO FETCH THUNK THEM
***This is my MainComponent.js file
import { postComment, fetchDishes, fetchComments, fetchPromos ,fetchLeaders ,postFeedback} from '../redux/ActionCreators';
const mapDispatchToProps = dispatch => ({
postFeedback: (firstname, lastname, telnum, email, agree, contactType, message) =>
dispatch(postFeedback(firstname, lastname, telnum, email, agree, contactType, message))
});
I suggest to update the mapDispatchToProps like this:
const mapDispatchToProps = dispatch => {
return {
postFeedback: () => dispatch(postFeedback),
}
}
Then call it in your component like this:
this.props.postFeedback(firstname, lastname, ...other args)

problem with fetch in componentDidMount()

my list of users is undefined when i try to console.log it.
Maybe i didn't get something ?
I'd like to get my list of users from my api who works (tested with postman) and put it into the console next i'd like to map my users to show it on the app
class Test extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
}
}
componentDidMount() {
console.log("component did mount");
fetch("/user/list")
.then(res => {
return res.json();
})
.then(users =>
this.setState({users}, () =>
console.log("list of users => " + users)));
}
render() {
return (
<div className="form">
<ul>
{this.state.users.map((user) =>
<li key="user._id">{ user.name }</li>
)}
</ul>
</div>
);
}
} export default Test;
Thanks for help !
You are calling res.json() rather than returning res.json() from the first then on your fetch call
I've found this pattern to be helpful:
fetch(url)
.then(res => res.ok ? res.json() : Promise.reject())
As your code is now, users (the parameter in the second then would be undefined, because you are not returning anything from the first then
you have to return the res.json() to use it in the next .then()
.then(res => {
res.json();
})
should be
.then(res =>
res.json();
)
Or
.then(res => {
return res.json();
})
https://javascript.info/promise-chaining
You should be passing your res into res.json() and returning the results into your state.
componentDidMount() {
console.log("component did mount");
fetch("/user/list")
.then(res => res.json())
.then(users =>
this.setState(users,
() => {
console.log("list of users => " + users)
})
);
}
Michael Jasper response help me so much!
I found that fetch with GET method does not work if we pass any request body.
the full example is here
https://github.com/alexunjm/todo-list-react
const buildRequestOptions = ({
method = "GET",
raw = null, // I had my error here!, with GET raw need to be null
customHeaders = {name: 'value'},
}) => {
var myHeaders = buildHeaders(customHeaders);
var requestOptions = {
method,
headers: myHeaders,
body: raw,
redirect: "follow",
};
return requestOptions;
};
const listTasks = () => {
const url = `${uriBase}/task/sample`;
const requestOptions = buildRequestOptions({
customHeaders: { "Content-Type": "application/json" },
});
return fetch(url, requestOptions);
}
const asyncFn = ({
promiseToWait,
pendingFn,
successFn,
errorFn,
}) => {
return (dispatch) => {
dispatch(pendingFn());
promiseToWait
.then((res) => {
if (res.ok) {
return res.json();
}
// handled from server status 422 and 401
if (res.status === 422) {
// error message on body from server
return res.json();
}
if (res.status === 401) {
// custom error message hardcoded
return {errors: {action: 'no authorized'}}
}
console.log("http response no controlled", res);
return Promise.reject();
})
.then((body) => {
if (body.errors) {
const errors = Object.keys(body.errors).map(
(key) => key + " " + body.errors[key]
);
dispatch(errorFn(errors.join("; ")));
} else {
dispatch(successFn(body));
}
return body;
})
.catch((error) => {
console.log("error", error);
dispatch(errorFn("Unavailable server connection"));
});
};
};
const queryTasks = () => {
return asyncFn({
promiseToWait: listTasks(),
pendingFn: apiPending,
successFn: apiSuccessList,
errorFn: apiError,
});
}

Resources