user6377312
user6377312

Reputation:

React Why cant I get the authentication token from asyncStorage 'on time'?

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

Answers (1)

Pankaj Sati
Pankaj Sati

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

Related Questions