기록하는 개발자

[React, Firebase] TwitterCloneCoding 1.0 Authentication-Google 로그인 본문

Web/React

[React, Firebase] TwitterCloneCoding 1.0 Authentication-Google 로그인

밍맹030 2021. 10. 12. 01:16
728x90

1. auth 사용을 위해 firebase.js에 import

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

const firebaseConfig = {
    apiKey: process.env.REACT_APP_API_KEY,
    authDomain: process.env.REACT_APP_API_AUTH_DOMAIN,
    projectId: process.env.REACT_APP_API_PROJECT_ID,
    storageBucket: process.env.REACT_APP_API_STORAGE_BUCKET,
    messagingSenderId: process.env.REACT_APP_API_MESSAGING_SENDER_ID,
    appId: process.env.REACT_APP_API_APP_ID,
};

initializeApp(firebaseConfig);

export const authService = getAuth()


2.App.js 에 firebase import

3. jsconfig.json 파일 생성
- 모든 경로가 src로부터 시작되는 것을 의미
ex) 기존 경로 : "../Router"  ->  jsconfig 적용 후 : components/Router

{
    "compilerOptions":{
        "baseUrl": "src"
    },
    "include": ["src"]
}

 

< 초기화면 > : login 하기 전 Google로 로그인 할 수 있는 Auth page가 rendering 된다.

login 전 firebase의 user tab

 

< 로그인 후 화면 > : login 후 Home과 Profile page가 rendering 된다.

login 후 firebase의 user tab

 

< Profile 클릭한 화면>

 

 

< Home.js >

import React from 'react';
const Home=()=><span>Home</span>;
export default Home;

< Navigation.js > : Home, Profile component의 Link를 가진다. 

import React from 'react';
import {Link} from "react-router-dom";

const Navigation = () =>(
    <nav>
        <ul>
            <li><Link to="/">Home</Link></li>
            <li><Link to="/profile">Profile</Link></li>
        </ul>
    </nav>
);

export default Navigation;

< Profile.js > : logout button이 있는 profile component

import { authService } from 'fBase';
import React from 'react';

export default ()=>{
    const onLogOutClick = () => authService.signOut();
    return <>
        <button onClick={onLogOutClick}>Log Out</button>
    </>;
};

< App.js >

import React, {useEffect, useState} from 'react';
import AppRouter from "./Router";
import { authService } from "../fBase";
import {onAuthStateChanged} from '@firebase/auth';

function App() {
  const [init, setInit]=useState(false);
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  useEffect(()=>{
      onAuthStateChanged(authService, (user) => {
        if(user!==null) setIsLoggedIn(true);
        else setIsLoggedIn(false);
        setInit(true);
    });
  },[]);

  return (
    <>
      {init ? <AppRouter isLoggedIn={isLoggedIn}/> : "Initializing..."}
      <footer>&copy; twitter {new Date().getFullYear()}</footer>
    </>
  );
}

export default App;

 

1.

const [init, setInit]=useState(false);

- 초기 setting : init 변수를 false 로 초기화하여 user 를 인식 하기 전까지 사용자가 접근하는 것을 막는 역할을 한다.

 

2.

const [isLoggedIn, setIsLoggedIn] = useState(false);
  useEffect(()=>{
      onAuthStateChanged(authService, (user) => {
        if(user!==null) setIsLoggedIn(true);
        else setIsLoggedIn(false);
        setInit(true);
    });
  },[]);

 

user가 인식 되었을 때(user의 상태 결정 전 == user의 존재 여부 결정 전)

 : onAuthStateChanged를 통해 user가 있는지 listen 중인 상태에서 user가 발견 되면 setIsLoggedIn을 이용하여 isLoggedIn의 상태를 설정한다.

 

user 상태 결정 후

 : 위 조건문을 통해 user의 존재 여부가 식별되었으므로 setInit을 통해 init 변수를 true로 초기화한다.

 

3.

 

  return (
    <>
      {init ? <AppRouter isLoggedIn={isLoggedIn}/> : "Initializing..."}
      <footer>&copy; twitter {new Date().getFullYear()}</footer>
    </>
  );
}

-  삼항 연산자를 통해 init이 true 인 경우 Home 또는 Auth를 띄우고, false인 경우 초기화 중이라는 의미로 "Initializing..." 문구를 띄운다.

- footer에 현재 날짜 중 년도를 표시한다.

 

 

< Router.js >

import React from 'react';
import {Redirect, HashRouter as Router, Route, Switch} from "react-router-dom"
import Auth from "../routes/Auth";
import Home from "../routes/Home";
import Profile from "../routes/Profile";
import Navigation from "./Navigation"

const AppRouter = (isLoggedIn)=>{
    const flag=isLoggedIn[Object.keys(isLoggedIn)[0]];

    return( 
        <Router>
            {flag&&<Navigation/>}
            <Switch>
                {flag? (
                    <> 
                        <Route exact path="/"><Home /></Route>
                        <Route exact path="/profile"><Profile /></Route>
                        <Redirect from="*" to="/" />
                    </>
                ) : (
                    <>
                        <Route exact path="/"><Auth /></Route>
                        <Redirect from="*" to="/" />
                    </>
                )}
            </Switch>
        </Router>
    );
}
export default AppRouter;

AppRouter

user 판별 후 화면을 띄울 때는 isLoggedIn값을 AppRouter에 보내 Home과 Auth 중 어떤 것을 띄울지 AppRouter가 결정한다.

const flag=isLoggedIn[Object.keys(isLoggedIn)[0]];

- isLoggedIn 이 AppRouter에 전달될 때 {isLoggedIn : value} 형식으로 전달되어 그냥 isLoggedIn 그대로 사용하면 object 로 간주되어 라우팅이 제대로 되지않았다. 이것 때문에 몇 시간을 고생하다가 object의 첫 번째 요소를 가져오자는 아이디어로 문제를 해결했다.

{flag? (
    <> 
        <Route exact path="/"><Home /></Route>
        <Route exact path="/profile"><Profile /></Route>
        <Redirect from="*" to="/" />
	</>
) : (
    <>
        <Route exact path="/"><Auth /></Route>
        <Redirect from="*" to="/" />
    </>
)}

user : !null → isLoggedIn : true 로 Home과 Profile을 반환한다.

user : null → isLoggedIn : false 로 Auth를 반환한다.

 

Log Out

※ profile 화면에서 logout 버튼을 클릭하면 logout이 되는데 이 때 해당 페이지에 머물러 있으며 home으로 돌아가지 않는다.

    → Redirect를 react-router-dom 으로부터 import하여 새로고침 시 자동으로 home으로 돌아도록 만든다.

<Redirect from="*" to="/" />

 

 

< Auth.js >

import { authService } from '../fBase'
import React from 'react'
import {GoogleAuthProvider, signInWithPopup} from '@firebase/auth'


const Auth=()=>{
    const onSocialClick = async (event) => {
        const { target: { name }} = event;
        let provider;
        if (name === "google") 
            provider = new GoogleAuthProvider();
        const data=await signInWithPopup(authService, provider);
    };

    return(
        <div>
            <button onClick={onSocialClick} name="google">
                sign in with Google
            </button>
        </div>
    );
}
export default Auth;

- google로 로그인하기 버튼 클릭 시 login 팝업 창이 뜬다.

728x90