[Firebase] STUDIO-로그인

Miog Yang·2022년 12월 1일
0

Project

목록 보기
6/7

기존 사용자 로그인 만들기

💡 firebase에 관련된 로직들은 firebase.js에서 만들고 필요한 컴포넌트에서 import하여 사용한다.

완료후 코드정리 👉 로그인/아웃, 상태관리 코드정리

//1.Google 공급자 인스턴스를 만들기

import { GoogleAuthProvider } from "firebase/auth";

const provider = new GoogleAuthProvider();
//2.Google 공급자 개체를 사용하여 Firebase에 인증.

import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";

const auth = getAuth();

signInWithPopup(auth, provider) //signInWithPopup을 사용하면 팝업창으로 인증
  .then((result) => {
    const credential = GoogleAuthProvider.credentialFromResult(result);
    const token = credential.accessToken;
    const user = result.user;
  }).catch((error) => {
    const errorCode = error.code;
    const errorMessage = error.message;
    const email = error.customData.email;
    const credential = GoogleAuthProvider.credentialFromError(error);
  });

1. Login

  • 의존성으로 인해 login()은 firebase에서 만든다.
  • 최대한 컴포넌트 내에서는 비즈니스로직을 담지 않는다.
  • firebase에서 로그인함수를 만들어서 Navbar컴포넌트에 적용한다.
  • import : getAuth,signInWithPopup,GoogleAuthProvider
  • firebase 로그인 : signInWithPopup
    📌 ref : Firebase 로그인
// api/firebase

import { initializeApp } from "firebase/app";
import { getAuth,signInWithPopup,GoogleAuthProvider } from "firebase/auth";

const auth = getAuth();

export async function login() {
  return signInWithPopup(auth, provider)
    .then((result) => {
      const user = result.user; // 사용자의 정보가 user안에 들어온다.
      console.log(user);
      return user;				// 사용자의 정보가 있다면 return
    })
    .catch(console.error); //catch(error => console.error(error))
  //콜백함수의 전달인자와 호출하는 인자가 동일할경우 생략가능
}
// components/Navbar.js
<Button text="Login" onClick={login}></Button>

  • 콘솔로 확인하고 받아온 user의 정보를 이용해서 UI작업까지 끝낸다.

2. Logout

  • Login과 같이 Logout도 만들어준다.
  • import : signOut
  • firebase 로그아웃 : signOut(auth)
    📌 ref : Firebase 로그아웃
// firebase 로그아웃

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});
// api/firebase  logout추가
import {
  getAuth,
  signInWithPopup,
  GoogleAuthProvider,
  signOut
} from "firebase/auth";

export async function logout() {
  return signOut(auth).then(()=>null);
}

3. Navbar Login/out

// component/Navbar.js

import { Link } from "react-router-dom";
import { FiShoppingBag, FiMenu } from "react-icons/fi";
import Button from "./ui/Button";
import { login, logout } from "../api/firebase;
import { useState } from "react";

function Navbar() {
  const [user, setUser]=useState();
  
  const handleLogin=()=>{
    login().then(setUser); //then( user => setUser(user))
  };
  
  const handleLogout=()=>{
    logout().then(setUser);
  };

  return (
    <header>
      <Link to="/">
        <h1>MIOGY STUDIO</h1>
      </Link>
      <nav>
        <Link to="/products">Products</Link>
        {!user && <Button text="Login" onClick={handleLogin}></Button>}
        {user && <Button text="Logout" onClick={handleLogout}></Button>}
      </nav>
    </header>
  );
}
export default Navbar;

🚧 로그인/로그아웃이 완성되었다.
여기서 로그인 상태에 새로고침을 하면 어떻게 될까? 그렇다. 새로고침을 하면 로그인한 상태를 보관하는 컴포넌트가 재렌더링되면서 상태도 다시 되돌아간다.

firebase에서는 사용자가 로그인하게 되면 로그인한 사용자의 정보 즉 세션을 보관하고 있다.
그래서 사용자가 새로고침을 해도 로그인한 사용자의 정보가 남아있다면 사용할수 있지만 현재 임의로 컴포넌트내에 user라는 state에 의존해서 로그인 만들었기 때문에 재렌더링하면 다시 state가 null로 바뀌는것을 볼수있다.
어떻게 해결할 수 있을까?

4. Firebase에 있는 onAuthStateChanged()사용하기

로그인한 사용자에 대한 정보가 필요한 각 앱 페이지에 대해 전역 인증 개체에 관찰자를 연결합니다. 이 관찰자는 사용자의 로그인 상태가 변경될 때마다 호출됩니다.
onAuthStateChanged 메서드를 사용하여 관찰자를 연결합니다. 사용자가 성공적으로 로그인하면 관찰자에서 사용자에 대한 정보를 얻을 수 있습니다.

📌 ref : onAuthStateChanged 사용하기

import { getAuth, onAuthStateChanged } from "firebase/auth";

const auth = getAuth();
onAuthStateChanged(auth, (user) => {
  if (user) {
    const uid = user.uid;
  } else {
    // User is signed out
    // ...
  }
});
//api/firebase  

import {
  getAuth,
  signInWithPopup,
  GoogleAuthProvider,
  signOut,
  onAuthStateChanged,
} from "firebase/auth";

//사용자의 상태를 확인추가
export function onUserStateChange(callback) {
  onAuthStateChanged(auth, (user) => {
    callback(user);
  });
}

  • 상태가 변경될때마다 콜백함수를 호출.
  • Navbar에서 useEffect를 사용하여 컴포넌트가 처음으로 마운트되었을때만 콜백함수가 담긴
    onAuthStateChange()호출한다.
// components/Navbar.js

import { Link } from "react-router-dom";
import { FiShoppingBag, FiMenu } from "react-icons/fi";
import User from "./User";
import Button from "./ui/Button";
import { login, logout, onUserStateChange } from "../api/firebase;
import { useState } from "react";

function Navbar() {
  const [user,setUser]=userState();
  
  useEffect(()=>{
    onUserStateChange((user)=>{
      setUser(user); // user가 변경될때마다 컴포넌트에 state를 변경
    })
  }, [])
  
  return (
    const handleLogin=()=>{
    login().then(setUser); //then( user => setUser(user))
  };
  
  const handleLogout=()=>{
    logout().then(setUser);
  };

  return (
    <header>
      <Link to="/">
        <h1>MIOGY STUDIO</h1>
      </Link>
      <nav>
        <Link to="/products">Products</Link>
        {!user && <Button text="Login" onClick={handleLogin}></Button>}
        {user && <Button text="Logout" onClick={handleLogout}></Button>}
      </nav>
    </header>
  );
}
export default Navbar;
  • firebase에서 생성한 onUserStateChange()를 useEffect안에 넣어서 처음에 한번 호출을 하고 onUserStateChange()안에 콜백함수를 사용하여 사용자의 로그인상태에 따라 state가 변경되게 만든다.



마치며

firebase로 만들어보는 로그인 간단한듯하지만 어렵다.
로그인기능을 위해 getAuth와 signInWithPopup가 필요하고 의존성으로 인해 firebase관련 로직들은 firebase내에서 관리한다.
로그아웃은 getAuth와 signOut이 필요하며 signOut에 auth를 담는다. (에러조심)
Navbar에서 state로 user의 상태를 관리하게 되면 새로고침시 재렌더링 되므로 firebase에서 제공하는 onAuthStateChanged()를 사용하여 사용자로그인 상태를 관리한다.
필요한것은 getAuth와 onAuthStateChanged이며 user를 callback에 담아 onUserStateChange라는 함수를 만들어 Navbar 컴포넌트에 useEffect에 담는다.
useEffect에 담긴 onUserStateChange함수는 처음 마운트될때 호출되고 콜백함수가 실행되면 user를 담아 상태에 따라 state가 변경된다.
여기까지 오늘의 정리 끝.

profile
주니어 개발사전 & 프론트엔드 도전기

0개의 댓글