React Hook , setvariable and print in same useeffect - reactjs

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) => {
...
});
}
})();

Related

How can i change from promise to async/await

How I can change the arrow function in my code to async/await syntax in google drive integration.
const listFiles = () => {
setLoading(true)
gapi.client.drive.files
.list({
pageSize: 500,
fields: 'nextPageToken, files(id, name, mimeType, modifiedTime)',
})
.then(function (response) {
setLoading(false)
const res = JSON.parse(response.body);
setDocuments(res.files);
});
};
the another one function I want to add async/await:
const initClient = () => {
setLoading(true)
gapi.client
.init({
apiKey: API_KEY,
clientId: CLIENT_ID,
discoveryDocs: DISCOVERY_DOCS,
scope: SCOPES,
})
.then(
function () {
setConnectStorage(true);
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
setLoading(false)
},
function (error) {
alert(error)
}
);
};
const listFiles = () => {
setLoading(true)
return new Promise((resolve, reject) => {
gapi.client.drive.files
.list({
pageSize: 500,
fields: 'nextPageToken, files(id, name, mimeType, modifiedTime)',
})
.then(function (response) {
setLoading(false)
const res = JSON.parse(response.body);
resolve(res.files)
});
})
};
const initClient = () => {
setLoading(true)
return new Promise ((resolve, reject) => {
gapi.client
.init({
apiKey: API_KEY,
clientId: CLIENT_ID,
discoveryDocs: DISCOVERY_DOCS,
scope: SCOPES,
})
.then(
function () {
setConnectStorage(true);
// gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
// updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
resolve({status: gapi.auth2.getAuthInstance().isSignedIn.get()})
setLoading(false)
},
function (error) {
reject({status: false})
}
);
})
};
Then run those functions:
(async () => {
const files = await listFiles()
const status = await initClient()
})()

React - how to wait for API response to return component?

I am new to react and I am building a page component that returns data from an API call and passes the values to my return statement. My page continues to return as blank because the page loads before the variables are returned from the API. I am wondering, how can I wait to render the page until my API has returned a response? The two variables are initialized as so and are not updated until the API response
var userData
const [customer_email, setEmail] = useState();
const [newuserid, setUserId] = useState();
useEffect(() => {
userData = Cookies.get("user-data");
if (userData) {
console.log("Userdata !== null");
try {
userData = JSON.parse(userData);
} catch (e) {
console.log(e);
}
setEmail(userData.email);
setUserId(userData.userID);
}
}, []);
function getCustomer() {
const options = {
method: "GET",
headers: {
Accept: "application/json",
"x-guid": "......",
"x-api-key": ".....",
},
};
if (customer_email != "" && customer_email != undefined) {
try {
console.log("email inside fetch =", customer_email);
fetch(
`https://exampleapi/customers?customer_email=${customer_email}&customer_id=${newuserid}`,
options
)
.then((response) => response.json())
.then((response) => console.log(response))
.catch((err) => console.log(err));
} catch (e) {
console.log(e);
}
}
}
if (customer_email) {
console.log("get customer");
getCustomer();
}
The component return statement:
return (
<>
{customer_email && (
<section>
<div
id="identification"
data-authenticated="true"
data-email={customer_email}
data-id={newuserid}
style={{ display: "none" }}
></div>
</section>
<div>
........{irrelevant html here}
</div>
)}
);
Note---- This is not a class, it is a function component
You might want to do something like this where you have a loading state that you set to true when the response from the API has been resolved, which will re-render the component.
Note: This code will not work if you copy and paste. It's just a representation of the pattern you should use.
var userData
const [customer_email, setEmail] = useState();
const [newuserid, setUserId] = useState();
cost [hasLoaded, setHasLoaded] = useState(false);
function getCustomer() {
const options = {
method: "GET",
headers: {
Accept: "application/json",
"x-guid": "......",
"x-api-key": ".....",
},
};
if (customer_email != "" && customer_email != undefined) {
try {
console.log("email inside fetch =", customer_email);
fetch(
`https://exampleapi/customers?customer_email=${customer_email}&customer_id=${newuserid}`,
options
)
.then((response) => response.json())
.then((response) => console.log(response))
.catch((err) => console.log(err));
} catch (e) {
console.log(e);
}
}
}
useEffect(() => {
userData = Cookies.get("user-data");
if (userData) {
console.log("Userdata !== null");
try {
userData = JSON.parse(userData);
} catch (e) {
console.log(e);
}
setEmail(userData.email);
setUserId(userData.userID);
}
}, []);
useEffect(async () => {
if (!customer_email) return;
console.log("getting customer")
const customerData await getCustomer()
if (customerData) setHasLoaded(true)
}, [])
return(
<>
{hasLoaded && <div>.....</div>}
</>
)

React Redux handling response after axios resubmit original request

I have a small booking program to practice ReactJS + Redux + ReduxSaga + Axios + Axios Interceptor + JWT authentication
Here is the code in the component BookingDialog after the submit button click
bookingDialog.js
const handleSubmit = (event) => {
event.preventDefault();
let payload = {
selectedDate: selectedDate,
carId : carDetail.id,
userId : user.login.id, //or pass by jwt accesstoken
remarks: remarks
}
console.log(payload);
dispatch(createBooking(payload));
}
And there is saga watcher which take latest of action createBooking to function handleCreateBooking
bookingSaga.js
export function* handleCreateBooking(action) {
try {
const response = yield call(createBooking, action.payload);
const { data } = response;
console.log("handleCreateBooking");
console.log(response);
if (data && data.result && data.result > 0){
console.log("booked successfully");
yield put(setMessageBarOpen({type: "success", content: "booked successfully"}));
yield put(setCreateBookingOpen(false));
}
else{
console.log("booked failed");
//yield put(setMessageBarOpen({type: "error", content: "booked failed"}));
//yield put(setCreateBookingOpen(false));
}
} catch (error) {
console.log(error);
}
}
bookingRequest.js
const createBooking = (payload) => {
return postUrl(apiURL.createBooking.url, payload).then((res) => {
return res
});
}
The program works as expected. Success message shown and booking dialog closed after submission.
If the jwt is expired, the program will retrieve the access token by refresh token and resubmit the original request with the new access token.
The problem is that, after the original request is sent and booking is created successfully, the follow up actions (setMessageBarOpen & setCreateBookingOpen) are not performed as the posting of original request is not under the function handleCreateBooking in bookingSaga.js
axiosInstance.js
import axios from 'axios';
import apiURL from "requests/apiURL";
const ax = axios.create();
ax.interceptors.request.use(
request => {
const accessToken = JSON.parse(localStorage.getItem('token')) && JSON.parse(localStorage.getItem('token')).accessToken;
if (accessToken) {
let auth = false;
for (const [key, value] of Object.entries(apiURL)) {
if (request.url.includes(value.url)) {
auth = value.auth;
break;
}
}
if (auth) {
request.headers.authorization = `Bearer ${accessToken}`;
}
}
return request;
},
error => {
return Promise.reject(error);
}
);
const sendRefreshToken = (refreshToken) => {
return new Promise((resolve, reject) => {
console.log("refreshToken");
postUrl(apiURL.token.url, { token: refreshToken })
.then((res) => {
console.log(res);
if (res.data) {
console.log(res.data);
localStorage.setItem('token', JSON.stringify({accessToken: res.data.accessToken, refreshToken: refreshToken}));
resolve(res);
}
})
.catch(error => {
reject(error);
});
})
}
ax.interceptors.response.use(
(response) => {
return response;
},
error => {
console.log("axios.interceptors.response");
console.log(error);
const status = error.response ? error.response.status : null;
const originalRequest = error.config;
let isRefreshing = false;
if (status === 403) {
if (!isRefreshing) {
const refreshToken = JSON.parse(localStorage.getItem('token')) && JSON.parse(localStorage.getItem('token')).refreshToken;
console.log("403, refreshToken:");
console.log(refreshToken);
isRefreshing = true;
sendRefreshToken(refreshToken)
.then(({ status }) => {
console.log(status);
if (status === 200 || status === 204) {
isRefreshing = false;
console.log("start resendRequest");
console.log(originalRequest);
return ax(originalRequest);
}
})
.catch(error => {
console.error(error);
});
}
}
return error;
}
);
export const getUrl = async (url, opt) => {
const response = await ax.get(url, opt);
return response;
}
export const postUrl = async (url, data, opt) => {
const axios_res = await ax.post(url, data, opt);
return axios_res;
}
How should I handle the response from the resubmitted original request?
Thanks.

Using the state hook to count inside of promises

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

How to return API data to a separate component - React Native

I am Fetching data from an API in my Native App and displaying it as a List.
Below is my code:
async componentWillMount() {
if (Platform.OS === 'android') {
BackHandler.addEventListener('hardwareBackPress', this.backPressed);
}
this.fetchNotifications();
}
}
async fetchNotifications() {
this.setState({refreshing: true});
const config = getAppConfig();
const cognitoToken = await this.getCognitoToken(config);
if (cognitoToken !== null) {
let headers = await this.getRequestHeaders(cognitoToken);
let body = this.getRequestBody(config);
let notificationUrl = config["notification-retrieve-api"];
return fetch(notificationUrl,
{
method: 'POST',
headers: headers,
body: body
}).then((response) => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong');
}
})
.then((notifications) => {
console.log(JSON.stringify(notifications));
this.setState({
notifications,
error: null,
refreshing: false
});
}).catch((error) => {
this.setState({
notifications: [],
error,
refreshing: false
});
});
}
}
This works fine. I can retrieve the data from the API.
Now I want to separate the API code from my screen component. I will be calling "fetchNotifications" as a function in my screen component. I am trying to do so but it's not working at all.
This is what I'm doing:
async componentWillMount() {
if (Platform.OS === 'android') {
BackHandler.addEventListener('hardwareBackPress', this.backPressed);
}
let response = fetchNotifications();
this.setState({
notifications: response,
error: null,
refreshing: false
})
}
}
async function fetchNotifications() { //now this function is in another component
.
.
.
.
if(cognitoToken !== null) {
let headers = await this.getRequestHeaders(cognitoToken);
let body = this.getRequestBody(config);
let notificationUrl = config["notification-retrieve-api"];
return fetch(notificationUrl,
{
method: 'POST',
headers: headers,
body: body
}).then((response) => {
if (response.ok) {
response.json();
} else {
throw new Error('Something went wrong');
}
})
.then((response) => {
return response;
}).catch((error) => {
this.setState({
notifications: [],
error,
refreshing: false
});
});
}
}
export default fetchNotifications;
Is this way correct? Anyone with a better solution?
My two cents, I always put async task in Promise, including API requests.
// API helper file
export const fetchNotifications = (params) => {
return new Promise(async (resolve, reject)=>{
try{
const headers = getHeaders(params)
const body = getBody(params)
const response = await fetch(notificationUrl,
{
method: 'POST',
headers: headers,
body: body
})
if (response.ok) {
const responseObj = await response.json();
resolve(responseObj)
} else {
throw new Error('Something went wrong');
}
} catch (e) {
// something went wrong
generalHandler(e) // logging etc.
reject(e) // for ui handling
}
}
}
then we can use it everywhere
import { fetchNotifications } from '.../APIHelper'
In your ui file :
componentWillMount() {
fetchNotifications(params)
.then((notifications) => {
console.log(JSON.stringify(notifications));
this.setState({
notifications,
error: null,
refreshing: false
});
}).catch((error) => {
this.setState({
notifications: [],
error,
refreshing: false
});
});
}

Resources