Reputation:
I'm using react native and need the authorization token from asyncStorage. I am using async/await and looked through all similar questions and don't understand why I m not getting the token 'in time' ? Any help would be great!!
const App = () => {
useEffect(() => {
const url = `${api_root_url}/stream`;
const getToken = async () => {
const token = await AsyncStorage.getItem('token');
if (token) {
return JSON.parse(token)
}
}
const token = getToken()
const eventSource = new EventSource(url, {
headers: {
Authorization: {
toString: function () {
return "Bearer " + token;
},
},
},
});
eventSource.addEventListener('open', () => {
console.log('SSE opened!');
});
eventSource.addEventListener('message', (e) => {
console.log(typeof (e.data), e.data);
const data = JSON.parse(e.data);
});
eventSource.addEventListener('error', (e) => {
console.error('Error: ', e);
});
return () => {
eventSource.close();
};
}, []);
}
Upvotes: 0
Views: 1017
Reputation: 2539
You need to await
the getToken()
method as well to finish reading the token.
Solution-
const App = () => {
useEffect(async () => { //Make the entire callback function an async to use await inside it
const url = `${api_root_url}/stream`;
const getToken = async () => {
const token = await AsyncStorage.getItem('token');
if (token) {
return JSON.parse(token)
}
}
const token = await getToken(); // Awaiting getToken() to execute and return value before executing the next line
const eventSource = new EventSource(url, {
headers: {
Authorization: {
toString: function () {
return "Bearer " + token;
},
},
},
});
eventSource.addEventListener('open', () => {
console.log('SSE opened!');
});
eventSource.addEventListener('message', (e) => {
console.log(typeof (e.data), e.data);
const data = JSON.parse(e.data);
});
eventSource.addEventListener('error', (e) => {
console.error('Error: ', e);
});
return () => {
eventSource.close();
};
}, []);
}
Elaboration on the comment by @Ozan Mudul -
getToken()
is an async function that returns a Promise. Promises are executed after your synchronous code because of the single-threaded nature of JS.Read more about Event loop, here
In the execution phase, JS engine executes this line and adds the promise returned by getToken() in microtask queue & its reference is held by your variable token
const token = getToken()
So, in the next line where you expect token to get added in the Authorization header, the constant token
still holds Promise instead of token value.
Awaiting getToken() method to return a value solves the problem
const token = await getToken()
Answering your question: "I am putting await inside the async function in from of AsyncStorage. I dont know why this isnt enough since the token wont be returned until I get that token because of the await."
const getToken = async () => {
const token = await AsyncStorage.getItem('token');
if (token) {
return JSON.parse(token)
}
}
Here, you are awaiting inside the getToken()
method. Whenever getToken() will be executed, it's first line i.e. const token = await AsyncStorage.getItem('token');
will await for Async Storage Promise to finish before executing the if condition in next line. Its not the same promise returned by your async method
This ensures you have the token before returning it. But this doesn't ensure execution of getToken()
method itself. So, you have to await getToken as well then executing it.
Upvotes: 2