본문 바로가기
Vue.js

[Vue.js][Error] Cannot read property 'signin2' of undefined

by 청양호박이 2021. 4. 7.

web application에 Google OAuth 2.0을 적용하는데 있어서, 발생할 수 있는 Error에 대해서 알아보겠습니다. 구현하는 방식은 Google Platform Library를 <script src />로 로딩하게 됩니다. 

 

이 경우, 정상적인 동작 Route는 

 

Library Load -> vue.js mounted hook 진입 -> gapi.signin2.render 

 

의 순서로 동작하게 됩니다. 

 

하지만, 네트워크의 상태나 기타 이유로.... Library Load가 늦어지고 vue.js의 mounted hook에 먼저 진입하게 되면 아래의 Error가 발생하게 됩니다.

 

vue.js mounted hook 진입 -> gapi.signin2.render Error

[Vue warn]: Error in mounted hook: "TypeError: Cannot read property 'signin2' of undefined"
TypeError: Cannot read property 'signin2' of undefined

이 Error는 한번도 해당 Library를 받은적인 없는 환경이나, 최근에 인터넷 사용 기록을 삭제한 경우에는 충분히 발생이 가능합니다. 

해당 Error가 발생하는 상황은 결국 Google SignIn button을 render하기 위한 gapi.signin2이 아직 생성되지 않은 상태가 되는 경우입니다. 따라서 해당 Error를 방지하기 위해서는... Library Load가 완료된 후에 vue.js에서 button을 render 해야 합니다.

 

이를 강제화 하는 방법은... 여러가지가 있겠지만 저는 web browser의 EventTarget.dispatchEvent( )를 사용해 보도록 하겠습니다. 세부적인 사용 방법은 아래의 주소를 참조했으며, 호환되는 web brower는 아래와 같습니다.

developer.mozilla.org/

developer.mozilla.org 제공

사용방법은 간단합니다. 

 

  1. create new Event constructor
  2. dispatch the event
  3. listen for the event and make a after function 

 

저는 Google Platform Library가 load되는 시점에 event를 발생시킬 것이기 때문에, index.html에 아래와 같이 코드를 변경해 줍니다.

 

[index.html]

    <script src="https://apis.google.com/js/platform.js?onload=init" async defer></script>
    <script>
      function init() {
        gapi.load('auth2', () => {
          gapi.auth2.init({ client_id: '[my_client_id].apps.googleusercontent.com' }).then(() => {
            console.log('init end!!');
            const event = new Event('google-oauth-library-load');
            window.dispatchEvent(event);
          });
        });
      }
    </script>

해당 library가 onload가 되면 init function을 호출하게 됩니다. 해당 function에서는 init을 하고나서 new Event를 생성하게 됩니다. 그리고 바로 dispatchEvent로 Event를 creating하게 되는 것이죠.

 

이렇게 되면, 전역으로 'google-oauth-library-load' 이름을 가진 Event가 생성되었습니다. 그럼 해당 이벤트를 받아서 사용할 코드를 원하는 곳에 작성해주면 됩니다. 저는 Login.vue에 기능을 구현하기 때문에 해당 파일에 addEventListener를 착성해 주겠습니다. 

 

[Login.vue]

  mounted() {
    window.addEventListener('google-oauth-library-load', this.renderSignInButton);
  },
  methods: {
    renderSignInButton() {
      window.gapi.signin2.render('my-signin2', {
        scope: 'profile email',
        width: 240,
        height: 50,
        longtitle: true,
        theme: 'dark',
        onsuccess: this.onSuccess,
        onfailure: this.onFailure,
      });
    },

기존에는 vue의 lifecycle중에서 mounted hook에 바로 render를 통해서 Google OAuth SignIn button을 그려줬는데... 이제는 Event를 받으면 해당 기능을 수행하는 로직으로 변경해 줍니다. 

 

addEventListener( )로 'google-oauth-library-load' 이름의 Event가 발생함을 감지하면, methods의 SignIn button을 그리기 위한 메서드를 실행시킵니다. 해당 변경사항으로 현재까지는 해당 button이 안뜨는 현상없이 잘 진행되고 있습니다. 

- Ayotera Lab -

댓글