본문 바로가기
Random

[Firebase] 소셜로그인 후 비동기적 처리

by SeanK 2022. 4. 16.

 

오늘 토이 프로젝트를 진행하다 결국 우려하던 일이 발생하고 말았다. 

 

Firebase의 구글 로그인 기능을 구현해 사용자가 로그인하면 사용자의 단어장 데이터를 받아오는 기능을 구현해야 했는데, 

 

사실 관련 부분은 나중에 생각해야지~ 하고 미뤄두었다가 오늘 사용자 로그인을 하며 단어장을 보려고 하니 문제가 생겼다. 

 

내가 의도했던 단어장 데이터를 가져오는 절차는 다음과 같았다. 

 

1. 사용자가 google 로그인 버튼을 클릭한다. 

2. google 로그인 페이지로 리디렉션 된다.

3. 로그인을 한다.

4. 다시 애플리케이션의 화면으로 돌아온다.

5. 사용자의 auth/state를 업데이트한다.

6. 사용자의 단어장 데이터를 firestore로부터 가져온다. 

 

문제가 생긴 원인으로는 5번과 6번이 동기적으로 처리되었기 때문이다. 정확히 말하자면 아직 사용자의 auth(state)가 업데이트되지 않았는데 텅 빈 사용자 id state를 이용해 firestore에 데이터 요청을 하니 아무런 데이터를 전달받지 못한 것이었다. 

 

따라서 실제로 이루어지고 있는 절차는 다음과 같았다. 

 

1. 사용자가 google 로그인 버튼을 클릭한다. 

2. google 로그인 페이지로 리디렉션 된다.

3. 로그인을 한다.

4. 다시 애플리케이션의 화면으로 돌아온다.

5. 사용자의 state를 업데이트하기 위해 auth에 데이터가 업데이트되기를 기다린다.

6. 사용자의 단어장 데이터를 firestore에 요청한다.

7. auth 업데이트가 완료된다.

8. firestore로부터 데이터 수신에 실패한다.

 

아무래도 firebase는 aws와는 다르게 즉각적인 데이터 송수신에서 약간의 단점을 가지는 듯하다. 

 

결국 이러한 문제를 해결하기 위해서는 auth 데이터가 완전히 업데이트가 되고 나서 데이터를 요청해야 한다.

 

비동기적 처리를 해야 한다는 건데... 이걸 어떻게 하지...?

이 부분에서 몇 시간 동안 완전히 멘붕상태에 빠져있었다. 왜냐하면 리디렉션으로 로그인이 처리되기 때문에 로그인 버튼에 프로미스를 생성해서 처리를 하려고 해도 이미 웹사이트는 다른 웹페이지로 이동해버려 콜백을 실행할 수가 없는 상태이기 때문이다. 

 

firebase의 옛날 코드들은 콜백 함수를 사용할 수 있도록 되어있는 것처럼 보이는데, 적어도 최신 버전에서는 불가능했다. 이것저것 많은 것을 실험해 봤지만 아래의 코드 이외에 추가로 할 수 있는 방법이 없었다.

//Google Oauth
  const provider = new GoogleAuthProvider();
  const googleSignIn = () => {
    signInWithRedirect(auth, provider);
  }

(SignIn.tsx)

 

getRedirectResult와 onAuthStateChanged

그러던 와중에 onAuthStateChanged라는 메서드를 발견했다! onAuthStateChanged는 '관찰자'라고도 불리는데, 관찰자라고 불리는 이유는 auth의 업데이트가 종료될 때까지 실행 과정을 관찰하다가 실행이 종료되는 순간 실행되는 일종의 리디렉션 로그인에서 '비동기적' 실행을 돕는 메서드다. firebase 감사합니다 ㅠㅠ

 

따라서 로그인 이후에 다시 돌아오는 페이지에서 getRedirectResult 메서드를 통해 리디렉션 되면서 전달되는 유저 정보를 redux state에 업데이트하면서 onAuthStateChanged로 auth가 변경되는 순간 firestore에 데이터를 요청하니 의도했던 프로세스를 통해 데이터를 전달받을 수 있었다. 

 

const updateStateAndGetDecks = () => {
      //Get google signin result and set user state
      getRedirectResult(auth).then( async (result: any) => {
        if (result) {
          const action = {
            userId: result.user.uid,
            email: result.user.email,
            img: result.user.photoURL,
            name: result.user.displayName,
            signin: true
          }
          dispatch(setUserState(action));
        }
      })

      onAuthStateChanged(auth, (res: any) => {
        //Fetch Decklist
        if (res) {
          const getDeckList = async () => {
            await dispatch(getDecks(res.email)).unwrap();
          };
          getDeckList();
        } else {
          dispatch(reset());
        }
      });
    }

 

확실히 firebase에 대한 블로그 자료는 상대적으로 많지 않은 듯하다. 다들 공식문서만으로 잘 해결해서 그런가... ㅠㅠ?

여하튼 리디렉션 이후 데이터 송수신 관련해서 어려움을 겪고 있다면 이 글이 도움이 되었길 바란다.