Use Async/Await in event handler in react - javascript

I have a function with two arrows, which sends some form data to my api via a POST request with fetch, once the form gets submitted. I want to make fetch asynchronous, but I really have no clue where the async keyword goes in this case.
//handles the submitting process
const handleSubmit = async (form_username, form_email, form_password) => (event) => {
event.preventDefault();
let data = {
username: form_username,
email: form_email,
password: form_password,
};
const response = await fetch(API + "/register", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
body: JSON.stringify(data),
});
};
The function would then be called via handleSubmit(param1, param2,...);
However, having the async keyword infront of the first params list returns the error unexpected reserved word 'await'
Any ideas where I should place the async keyword in order to actually make it async?
Thanks in advance!

Your async is declared on the wrong function: it should be the inner function that is being returned, since it is the one that contains the await keyword:
const handleSubmit = (form_username, form_email, form_password) => async (event) => {
// Rest of the logic here
}

Related

How to add path variables to fetch api in Javascript?

Im using mockapi for a very simple project. In order to change data, i have to send PUT request. I can send the request using PostMan like in the pictures below. And everything works perfect. But i don't know where to add path variables in fetch api using Javascript. I know how to add body and i know how to add headers but i cannot figure out where to add path variables.
My code is:
async function getData() {
let url = "https://blablabla/moves/:id";
const fetchData = {
method: "PUT",
body: {
roomid: 2512,
move: "move 2",
id: 2,
},
headers: new Headers({
"Content-Type": "application/json; charset=UTF-8",
}),
};
await fetch(url, fetchData)
.then((response) => response.json())
.then((data) => console.log(data));
}
And the Postman Screenshot:
Postman Screenshot
I added the key: id part. All i want to know is that how can i add the "value: 2" part (that you can see in the picture) to fetch api. Any help will be appreciated.
I tried to fetch PUT request in javascript but couldn't figure out where to put Path Variables.
There are no path variables in the fetch api, but you can pass the id in the string itself like so:
async function getData(id) {
let url = `https://blablabla/moves/${id}`; // use string interpolation here
const fetchData = {
method: "PUT",
body: {
roomid: 2512,
move: "move 2",
id: 2,
},
headers: new Headers({
"Content-Type": "application/json; charset=UTF-8",
}),
};
await fetch(url, fetchData)
.then((response) => response.json())
.then((data) => console.log(data));
}

Javascript how to pass data between two <script> within <head>

Does anyone know how to use data that was calculated in one script in another script?
For example within head this script gets a customer email
Edit: Added var customer_email; but getting undefined when using customer_email outside of loadSuccess() function.
<script>
var customer_email;
async function loadSuccess() {
const response = await fetch('/.netlify/functions/success', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
}).then((res) => res.json())
.catch((err) => console.error(err));;
customer_email = response.session.customer_details.email;
console.log(customer_email);
}
loadSuccess();
console.log(customer_email);
}
</script>
<script>
console.log(customer_email);
</script>
Now in a different also within , how can customer_email be used?
In this example, only the 1st console.log(customer_email) within loadSuccess() prints the email. The other 2 print undefined.
Make customer_email a global variable
<script>
var customer_email;
async function loadSuccess() {
const response = await fetch('/.netlify/functions/success', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
}).then((res) => res.json())
.catch((err) => console.error(err));;
customer_email = response.session.customer_details.email;
}
loadSuccess();
}
</script>
You are able to assign your value to a global variable, such as window._customer_Email.
window._customer_Email = response.session.customer_details.email;
Then you can access this in the same way
console.log(window._customer_Email)
Note that global variables are something recommended against because they cannot be garbage collected easily and also pollute the global state (risking conflicts)

Chaining fetchs 'POST' in a React component

I believe my problem might have been answered more or less but I can't find a satisfactory response. I have a React form with an input and onChange lets you select a picture that immediately gets saved in the cloud. The cloud returns a response with an url and an id that I want to pass to the backend database, thus submitted with the form handleFormSubmit. The code below succeeds only if I wait until I get back the response from the cloud (I watch the Dev Tools Components). If I am to quick, the url is 'undefined' because the promise is not set. How can I programmatically properly chain these promises?
I use a state 'photoUrl' for the url and an object called 'Event'.
handling the file input onChangeand send to the cloud and get response back:
async function handleSendToCloudinary(e){
if (e.target.files[0]){
const formdata = new FormData()
formdata.append('photo', e.target.files[0])
fetch(CL_end_point, { method: 'POST', body: formdata})
.then(res=> res.json())
.then(data=> setPhotoUrl(data))
}
}
and the onSubmit on the global form:
async function handleFormSubmit(e){
e.preventDefault()
const formdata = new FormData()
if (photoUrl) {
formdata.append('url', await photoUrl.secure_url)
formdata.append('key', await photoUrl.product_id)
}
try {
setEvents(
await fetch(myEndPoint, { method: 'POST', body: formdata })
}...
I believe something around Promise.all might give a clue but I can't get the solution.
Something like the following fails ('object not iterable')
const p1 = new Promise((resolve)=> {
resolve(formdata.append('url', photoUrl.secure_url)
})
cont p2 = new Promise((resolve) => {
resolve(formdata.append('key', photoUrl.product_id)
})
Promise.all([p1,p2]).then(()=> {
setEvents(...)})
and the following fails too because of the state photoUrl update probably
const p1 = (formdata)=> {
formdata.append('url', photoUrl.secure_url)
return promise.resolve(formdata)
}
I think you need to introduce a loading flag to your state
const [loading, setLoading] = useState(false)
Then you set it to true when uploading your file:
async function handleSendToCloudinary(e){
if (e.target.files[0]){
setLoading(true)
const formdata = new FormData()
formdata.append('photo', e.target.files[0])
fetch(CL_end_point, { method: 'POST', body: formdata})
.then(res=> res.json())
.then(data=> setPhotoUrl(data))
.finally(() => setLoading(false))
})
}}
And then you disable your submit button while loading is true
As a last note, the complexity of your form handling is going to pile up as the time goes (certainly you'd want to handle errors in the future) so you might as well start looking up react state managers and their async handlers (redux and redux-thunk come to my mind first) in order to move your business-logic away from your components

Reading token from AsyncStorage before a fetch call

In my ReactNative app, I'm trying to come up with a nice pattern to read the access_token I store in AsyncStorage and use it in a fetch call.
In other words, I want to create a pattern that uses some type of wrapper that makes sure that the fetch call always has the access_token it needs. So execution order should always be:
Invoke Fetch Call -> Get Token from AsyncStorage and Prep Header -> Execute Fetch Call
I came up with the following code but it looks like I'm having problems with the Async part of AsyncStorage and my fetch calls are going out without the token.
Here's my fetch call:
export const someApiCall = (request) => {
const url = 'https://myapi.com/add';
return (dispatch) => fetch(url, fetchOptionsPost(request))
.then((response) => {
if (response.ok && response.status === 200) {
// Got data. Dispatch some action
}
})
}
Here, I'm using a helper function to prepare the headers, etc. Here's what the fetchOptionsPost() looks like:
export const fetchOptionsPost = (request) => {
getAccessToken()
.then(token => {
return {
method: 'POST',
mode: 'cors',
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + token
},
body: JSON.stringify(request)
}
});
};
And the getAccessToken() function simply reads it from AsyncStorage as below:
export const getAccessToken = async () => {
return await AsyncStorage.getItem("access_token");
}
This pattern is NOT working and API calls are going out without a token.
I also want to mention that if I hard-code the token inside my fetchOptionsPost() method, everything works fine. Clearly, the issue here is that the fetchOptionsPost() is not returning anything.
What can I do to make sure that I will ALWAYS have my token in my fetchOptionsPost?
you could add token call inside someApiCall function .And also create the options on inside the function . function was async so fetch only run after get token result
Updated
const fetchOptionsPost = (token) =>{
return ({
method: 'POST',
mode: 'cors',
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + token
}
})
}
export const someApiCall = async(request) => {
const token = await AsyncStorage.getItem("access_token");
const url = 'https://myapi.com/add';
fetch(url, fetchOptionsPost(token))
.then(response=>response.json())
.then((data)=>{
// call the dispatch here
})
}
Why use async inside on main function
AsyncStorage only have async callback. if you are set the AsyncStorage as separate function you should call async for the both function.Thats why i added with in parent async function and pass the token to fetchOptionsPost
Here's what I've come up with which seems to work fine. I still would appreciate any suggestions or improvements to this code.
First, here's what my fetch call looks like now. I wrapped it inside the getAccessToken() function which is an async call but because I'm using redux-thunk, I'm able to do this.
export const someApiCall = (request) => {
const url = 'https://myapi.com/add';
return (dispatch) => getAccessToken()
.then(token => {
fetch(url, fetchOptionsPost(request, token))
.then((response) => {
if (response.ok && response.status === 200) {
// Got data. Dispatch some action
}
})
})
}
I slightly changed my fetchOptionsPost() helper function which now accepts the token. It's also a bit more robust now. If it doesn't get a token, it simply omits the Authorization part in the header. I opted for this approach as some calls to my API backend do not require authentication. Also the isValidString() is another helper validation function I created to make sure I do get a valid string. It returns a TRUE or FALSE response based on the string value inputed:
export const fetchOptionsPost = (data, token = null) => {
if (isValidString(token)) {
return {
method: 'POST',
mode: 'cors',
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + token
},
body: JSON.stringify(data)
}
} else {
return {
method: 'POST',
mode: 'cors',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
}
}
};
And finally, the getAccessToken() function which didn't really change but here it is:
export const getAccessToken = async () => {
return await AsyncStorage.getItem("access_token");
}
As I said, I'd appreciate any comments or suggestions on further improving this code.
Hope this is useful to others.
Use Async and await method and get the token before each call.
async ()=>{
let token =await getTokenFromLocal();
return (dispatch) => fetch(url, fetchOptionsPost(request))
.then((response) => {
if (response.ok && response.status === 200) {
// Got data. Dispatch some action
}
})
}

React-native async fetch returns null

I am trying to put fetch functions into a separated file, so I can organise these API fetch easily. However, when I try to fetch and return the data, it gives me null or an unexpected json object. Here is part of my src:
//api.js
export async function LoginAPI(username, password) {
const url = baseURL + "/login/";
var params = {username: username, password: md5.hex_md5(password)};
let response = await fetch(url, {
method: 'POST',
headers: {'Accept': 'application/json','Content-Type': 'application/x-www-form-urlencoded'},
body: JSON.stringify(params)
});
return await fetch(url, {
method: 'POST',
headers: header,
body: JSON.stringify(params)
})
.then((res) => res.text())
.then((text) => text.length ? JSON.parse(text) : {})
.catch((error) => {
throw error;
});
};
Here is the another file.
//index.js
var Login = React.createClass({
onPress_login: function() {
var value = this.refs.form.getValue();
if (value) {
result = LoginAPI(value.username, value.password);
console.log(result);
} else {
this.AlertDialog.openDialog();
}
},
render() {
return (
(...)
<Button onPress={this.onPress_login}>
<Text>Login</Text>
</Button>
The fetch is working, it is communicating with the server. However, the console log returns me this at the first place
Promise _45: 0_54: null _65: null _81: 1 __proto__: Object
I am assuming that the result log in the console at the first place is not the await result (the actual response from server, but an object of fetch response). I tried to search out methods online but I can't find any post/blog/article saying how to do fetch as a function call.
Is there any way to do like swift, LoginAPI(username, password, callback: {...}) please?
The problem is that you're are making an async function and not waiting for the response, the you see that kind of console log.
Try this:
result = await LoginAPI(value.username, value.password);
Let me know if this was your problem.

Categories

Resources