본문 바로가기
  • soldonii's devlog
Javascript 공부/React

리액트로 google 로그인 추가하기

by soldonii 2019. 12. 17.

*Udemy의 "Complete React Developer in 2020" 강의에서 학습한 내용을 정리한 포스팅입니다.

*자바스크립트와 리액트를 배우는 단계라 오류가 있을 수 있습니다. 틀린 내용은 댓글로 말씀해주시면 수정하겠습니다. 감사합니다. :)


1. Google Authentication 추가하기

리액트에 google 로그인 기능을 추가하려면 우선 firebase 패키지를 설치해주어야 한다. 프로젝트 폴더에 들어간 후, yarn add firebase 로 해당 패키지를 추가해준다. 이후 아래처럼 새로운 파일을 생성한 후 importing한다.

// firebase.utils.js 파일 새롭게 생성하기
import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';

첫번째 import는 설치한 firebase 전체를 불러오는 것이다. 하지만 firebase는 꽤 커다란 라이브러리이므로, 우선 불러온 후 필요로 하는 기능만을 선택적으로 추가로 import한다. 우선은 firestore와 auth 만을 추가로 import한다. firestore는 database관련, auth는 user authentication 관련된 기능이다.

 

이후 firebase SDK에서 내가 등록한 wep app의 firebase configuration이 담겨있는 객체를 변수에 할당하고, initializeApp을 한다.

const config = {
  apiKey: "AIzaSyAKkH1AmLj9r7dvP4m0bRgCtnlLS8IX0s0",
  authDomain: "crwn-db-a32cc.firebaseapp.com",
  databaseURL: "https://crwn-db-a32cc.firebaseio.com",
  projectId: "crwn-db-a32cc",
  storageBucket: "crwn-db-a32cc.appspot.com",
  messagingSenderId: "849897368177",
  appId: "1:849897368177:web:bc4154bc855ca4cc5d09d0",
  measurementId: "G-SE2H8CM5G7"
};

firebase.initializeApp(config);

이후 아래의 코드를 추가한다.

export const auth = firebase.auth();
export const firestore = firebase.firestore();

const provider = new firebase.auth.GoogleAuthProvider();
// GoogleAuthProvider 클래스를 authentication 라이브러리에서 사용할 수 있도록 불러오는 코드.
provider.setCustomParameters({prompt: 'select_account'});
// signIn이랑 authentication을 위해서 GoogleAuthProvider를 사용할 때마다 구글 팝업을 항상 띄우기를 원한다는 의미이다.
export const signInWithGoogle = () => auth.signInWithPopup(provider);
// signInWithPopup 메소드는 여러 파라미터를 받을 수 있다. 트위터, 페이스북, 깃허브 등으로도 로그인이 필요할 수도 있으므로.
// 여기에서는 google로 signIn할 것이기 때문에, 파라미터로 위에서 정의한 provider를 넣어준다.

export default firebase;
// 혹시 전체 라이브러리가 필요할지도 모르기 때문에 firebase도 export 해준다.

이후 firebase 콘솔의 authentication에서 google을 enable한다.

google로 로그인하길 원할경우 google을 사용 설정됨으로 변경하고 저장한다.

 

이후 SignIn 컴포넌트에서 위에서 만든 firebase.utils.js 파일을 import하고, 구글 로그인 기능을 덧붙일 버튼에 onClick 프로퍼티의 값으로 signInWithGoogle 메소드를 붙여준다.(signInWithGoogle 메소든느 firebase.utils.js 에서 정의한 메소드이다.)

// sign-in.component.jsx 파일
import { signInWithGoogle } from '../../firebase/firebase.utils';

<CustomButton type="submit" value="Submit Form">SIGN IN</CustomButton>
<CustomButton onClick={signInWithGoogle}>SIGN IN WITH GOOGLE</CustomButton>

첫번째 CustomButton 컴포넌트는 일반 sign in, 두번째 컴포넌트는 구글로 sign in 하는 버튼이다.

 

2. SignIn 혹은 SignOut 여부를 알 수 있도록 추가하기

위까지 작업을 완료하면 구글 계정으로 로그인이 가능하다. 하지만 signIn이 된 것인지, 또는 signout을 한 것인지를 user가 알 방법이 없으므로 이를 알 수 있도록 컴포넌트를 추가해주자.

우선 App.js에서 firebase.utils.js를 import한 후, state가 필요하게 되므로 함수형 App 컴포넌트를 클래스 기반으로 변경시키자. 이후 this.state = {currentUser: null}로 초기화해준다.

import React from 'react';
import { Route, Switch } from 'react-router-dom';

import HomePage from './pages/homepages/homepage.component';
import ShopPage from './pages/shop/shop.component';
import Header from './components/header/header.component';
import SignInAndSignUpPage from './pages/sign-in-and-sign-up/sign-in-and-sign-up.component';
import { auth } from './firebase/firebase.utils';
import './App.css';

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      currentUser: null
    }
  }

  componentDidMount() {
    auth.onAuthStateChanged(user => {
      this.setState({ currentUser: user });
    })
  }

  render() {
    return (
      <div>
        <Header />
        <Switch>
          <Route exact path="/" component={HomePage}/>
          <Route path="/shop" component={ShopPage}/>
          <Route path="/signin" component={SignInAndSignUpPage}/>
        </Switch>
      </div>
    );
  }
}

export default App;

 

이후 componentDidMount 내부에서 import한 google auth에서 제공되는 onAuthStateChanged 메소드를 이용하자. 여기만 떼놓고 보면,

componentDidMount() {
  auth.onAuthStateChanged(user => {
    this.setState({ currentUser: user });
  })
}

유저가 로그인한 상태가 변경될 경우, state의 값을 변경시키게 하고 있다. 유저가 로그인 한 경우, 로그인 한 유저의 정보가 this.state.currentUser에 담기게 된다. 만약 로그아웃을 하면 다시 this.state.currentUser에 null이 담긴다. 유저가 로그아웃하지 않는 이상, 창을 끄거나 새로운 탭에서 페이지에 들어가도 로그인 정보는 그대로 유지된다.

 

만약 새로운 유저가 로그인하거나, 혹은 기존 유저가 로그아웃 하는 등 user 데이터에 변경이 생기면, google firebase auth 라이브러리가 우리 앱에 메세지를 보내준다. 따라서 변경이 일어날 때마다 수동으로 user 데이터를 fetch하지 않고 자동으로 상태가 변경된다. 이러한 open subscription은 App 컴포넌트가 DOM에 존재하는 한 유효하다. 하지만 DOM에서 App 컴포넌트가 unmount될 경우, 이 과정을 멈춰주지 않으면(close subscription) 메모리 누수가 발생한다.

 

unsubscribeFromAuth = null;

componentDidMount() {
  this.unsubscribeFromAuth = auth.onAuthStateChanged(user => {
    this.setState({ currentUser: user });
  });
}

componentWillUnmount() {
  this.unsubscribeFromAuth();
}

따라서 최초에는 unsubscribeFromAuth라는 변수를 만든 후 null을 넣어두고, 만약 user 정보가 변경되면 auth.onAuthStateChanged 메소드가 리턴시키는 함수를 unsubscribeFromAuth 변수에 담아둔다. 이후 App 컴포넌트가 unmount되면 이 값이 호출되도록 해주면 close subscription이 가능하다.

 

3. SignOut 표시해주기

import React from 'react';
import { Link } from 'react-router-dom';
import { ReactComponent as Logo } from '../../assets/crown.svg';
import { auth } from '../../firebase/firebase.utils';
import './header.styles.scss';

const Header = ({currentUser}) => (
  <div className="header">
    <Link to="/" className="logo-container">
      <Logo className="logo"/>
    </Link>
    <div className="options">
      <Link className="option" to="/shop">SHOP</Link>
      <Link className="option" to="/shop">CONTACT</Link>
      {
        currentUser ?
          <div className="option" onClick={() => auth.signOut()}>SIGN OUT</div>
          :
          <Link className="option" to="/signin">SIGN IN</Link>
      }

    </div>
  </div>
)

export default Header;

Header 컴포넌트에서 signIn 혹은 signOut을 알 수 있도록 해주는 코드이다. 

1. 우선 auth 를 import한다.

2. App.js에서 Header에게 props로 넘겨준 currentUser 정보를 전달 받고, 만약 이것이 null이면 Sign In Link 컴포넌트를, null이 아니라 유효한 값이 들어있으면 Sign Out div가 보여지도록 한다.

3. signOut의 경우, onClick 프로퍼티를 달고, 전달되는 값은 auth.signOut()을 전달한다. 이는 auth 라이브러리에 의해서 제공되는 기능으로, 로그인 된 유저가 로그아웃되도록 하는 기능이다.

 

 

댓글