로그인 과정에서 google OAuth 인증이 끝나면 해당 토근을 가지고 우리 서버에서 jwt 토큰을 발급한다. 그리고 유저 정보를 받아오는데 이때 해당 토큰을 헤더에 넣어서 요청을 보내야 한다.
그런데 문제가 하나 있었다.
// ...
const getUserInfo = useCallback(async () => {
try {
const localResponse = await Api.getUserInfo(accessTokenRef.current);
return localResponse;
} catch (e) {
Sentry.captureException(e);
}
}, []);
const handleToken = useCallback(async () => {
// ...
if (response?.type === 'success') {
const token = response.authentication?.idToken;
if (token) {
await getToken({ token });
const user = await getUserInfo();
await AsyncStorage.setItem('userId', user.id.toString());
await AsyncStorage.setItem('userName', user.username);
//...
여기서
const user = await getUserInfo(); 이후에 user 값이 undefined라서 user.id에서 id라는 속성에 접근을 할 수 없다고 한다.
그런데 놀라운 점은
// ...
const getUserInfo = useCallback(async () => {
try {
const localResponse = await Api.getUserInfo(accessTokenRef.current);
console.log('response ', localResponse) // 이 자리에 콘솔 로그
return localResponse;
} catch (e) {
Sentry.captureException(e);
}
}, []);
// ...
이렇게 콘솔로그를 중간에 찍으면 문제없이 동작한다.
그렇다면 비동기에서 문제가 있다는 것인가?
// ...
const getUserInfo = useCallback(async () => {
try {
const localResponse = await Api.getUserInfo(accessTokenRef.current);
console.log('1 ', localResponse) //순서확인 1번째
return localResponse;
} catch (e) {
Sentry.captureException(e);
}
}, []);
const handleToken = useCallback(async () => {
// ...
if (response?.type === 'success') {
const token = response.authentication?.idToken;
if (token) {
await getToken({ token });
const user = await getUserInfo();
console.log('2 ', user) // 순서확인 2번째
await AsyncStorage.setItem('userId', user.id.toString());
await AsyncStorage.setItem('userName', user.username);
//...
그래서 디버거로 확인을 해보았는데, const user = await getUserInfo();에 브레이크 포인트를 두었고 저 위치에서 잘 멈췄었다. 그래서 그 다음줄로 넘어가려고 했는데 step into를 눌러도, step over를 눌러도 계속 react native인지 라이브러리인지 내부적으로 동작하는 코드 속으로 타고 들어가다가 어느 시점에서 무한 재귀가 걸리듯 같은 곳을 뱅글뱅글 도는 문제가 있었다. 어떤 문제인지 어떻게 해결할지 감이 안와서 일단 콘솔로그를 찍어보았다. 이전 로그에서 보았을 때 getUserInfo 함수 내에서는 user 값이 잘 들어왔었다. 그래서 받아온 뒤 return하는 과정에서 값이 사라지는 것인지 알이보기 위해 로그를 찍어보았는데 찍고보니 로그 찍히는 순서가 반대인 것이었다.
LOG 2 undefined
LOG 1 {"email": "", "id": 2, "socialProvider": "GOOGLE", "username": "<생략>"}
분명 await인 const user = await getUserInfo();이 부분이 다 끝나야 그 아래 줄에 있는 로그가 찍혀야할텐데 왜 이럴까
비동기에 대해 찾아보았다.
[Javascript] 비동기, Promise, async, await 확실하게 이해하기
Async&Await 쉬운 설명 | Promise, async/await 끝장내기 강의 EP_05
MDN async function
[Javascript 미세팁] 비동기처리는 무조건 async/await 아닌가요?
https://forum.freecodecamp.org/t/await-not-working-in-react/509235
나와 비슷한 사람을 찾았는데 이 사람은 await이 안멈추는 부분 이후 코드를 useEffect에 넣어서 해결했다.
내가 생각해본 이유로는
1. getUserInfo가 Promise를 반환하지 않아서 즉 비동기가 아니라서
2. Promise에서 resolve가 되면 await으로 기다리던게 풀리니까 getUserInfo의 어디선가 모르게 resolve가 되어버린 것인가
정도를 생각해보다가
문뜩 코드를 보니 Api.getUserInfo(accessTokenRef.current)로 유저 데이터를 받아오고 있는데 굳이 한번더 이걸 비동기 함수로 감싸서 리턴을 해야 하는가라고 생각이 들었고
//...
if (response?.type === 'success') {
const token = response.authentication?.idToken;
if (token) {
await getToken({ token });
const user = await Api.getUserInfo(accessTokenRef.current);
/...
감싸던 getUserInfo를 빼고 보니 문제가 사라졌다.
근본적인 원인이 무엇이었는지는 더 생각해보아야 할 것 같다.