Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

Joon's Space

[React] React + Firebase 연동 (setup, login, profile) (1) 본문

Web/React

[React] React + Firebase 연동 (setup, login, profile) (1)

Happy Joon 2022. 2. 16. 22:34

※ nomadcoder twitter clone coding 강의 참고

React + Firebase setup

- React 프로젝트 생성

npx create-react-app 프로젝트명

 

- firebase 모듈 설치

npm install firebase

 

- Firebase 프로젝트 생성

src/firebase.js을 생성하여 홈페이지에서 생성된 firebaseConfig를 저장하고 initiallizeApp으로 실행

// src/firebase.js

import * as firebase from "firebase/app";

const firebaseConfig = {
    apiKey: process.env.REACT_APP_API_KEY,
    authDomain: process.env.REACT_APP_AUTH_DOMAIN,
    projectId: process.env.REACT_APP_PROJECT_ID,
    storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
    messagingSenderId: process.env.REACT_APP_MESSAGIN_ID,
    appId: process.env.REACT_APP_APP_ID
};

export default firebase.initializeApp(firebaseConfig); // index.js에서 사용을 위함

root에 .env 파일을 생성하여 key값을 저장 (git에 업로드되어서 공개되지 않기 위함)

 

// src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import firebase from "./firebase";

console.log(firebase);

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

위와 같이 작성 후, App을 실행하면 브라우저 콘솔창에 firebase 정보가 표시되니, 연동이 잘 되었음을 확인.

 

// components/Router.js

import React, { useState } from "react";
import { HashRouter as Router, Route, Routes } from "react-router-dom";
import Auth from "../routes/Auth";
import Home from "../routes/Home";

const AppRouter = () => {
    const [isLoggedIn, setIsLoggedIn] = useState(false);
    return (
        <Router>
            <Routes>
                {isLoggedIn ? (
                <>
                <Route path="/" element={<Home/>}/>
                </> 
                ) : (
                <Route path="/" element={<Auth/>}/>
                )}
            </Routes>
        </Router>
    );
};

export default AppRouter;

react v6 버전으로 넘어 오면서 Route의 부모 요소인 Switch 가 -> Routers로 이름이 변경,

그리고 Route의 exact 옵션이 사라지고 path만 남게됨, component로 사용하지 않고 element 방식으로 사용되어 <Home />, <Auth />처럼 뾰족 괄호도 넣어 줘야 한다.

 

Authentication

firebase에서는 authentication 기능도 제공하는데 firebase/auth 에서 getAuth() 함수를 import 한다.

// fbase.js

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

const firebaseConfig = {
    apiKey: process.env.REACT_APP_API_KEY,
    authDomain: process.env.REACT_APP_AUTH_DOMAIN,
    projectId: process.env.REACT_APP_PROJECT_ID,
    storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
    messagingSenderId: process.env.REACT_APP_MESSAGIN_ID,
    appId: process.env.REACT_APP_APP_ID
};

initializeApp(firebaseConfig); // index.js에서 사용을 위함
export const authService = getAuth();

fbase.js 를 다음과 같이 수정해 준다. 앞으로 getAuth 기능을 자주 사용할 것이기 때문에, authService로 선언하여 사용한다.(export)

 

console.log(authService.currentUser)

App.js 에서 getAuth()함수의 currentUser를 보면 반환하면 아직 아무 유저도 인증되지 않았기 때문에 null값을 반환한다. 이 값을 isLoggedIn state값 변수로 사용할 수 있다.

 

Google, Github 로그인 생성

 

firebase 콘솔에서 authentication에 가면 다음과 같이 로그인에 사용할 플랫폼을 추가할 수 있다.

 

계정 생성, 로그인

firebase auth의 createUserWithEmailAndPassword, signInWithEmailAndPassword 함수를 사용 

- createUserWithEmailAndPassword( getAuth(), email:string, password:string) : Promise <UserCredential> 

- signInWithEmailAndPassword( getAuth(), email: string, password: string) : Promise <UserCrediential> 

 

// Auth.js

const onSubmit = async(event) => {
    event.preventDefault();
    try {
        let data;
        const auth = getAuth();
        if(newAccount) {
            // create account
            const data = await createUserWithEmailAndPassword(auth, email, password);
        } else {
            // log in 
            const data = await signInWithEmailAndPassword(auth, email, password);
        }
        console.log(data);
    } catch (error) {
        console.log(error);
    }
}

 

로그인 상태 확인

firebase/auth 의 onAuthStateChanged() 함수를 통해서 user가 존재하면 isLoggedIn 값을 true, 존재하지 않은 경우 isLoggedIn 값을 false로 변경한다.

 

이때 useEffect() 함수를 사용하고, 컴포넌트가 처음 로딩될 때만 확인하면 되기 때문에, 두 번째 deps 파라미터는 비워준다.

(두 번째 deps 파라미터에 값을 넣으면 입력한 값이 변경될 때마다, useEffect에서 첫 번째 파라미터인 함수가 실행된다. )

// App.js

const [isLoggedIn, setIsLoggedIn] = useState(false);

// 컴포넌트가 처음시작될 때 확인만 하는 작업이니 2번째 파라미터는 비워준다.
  useEffect(() => {
    onAuthStateChanged(authService, (user) => {
      if(user) {
        // logged in 
        setIsLoggedIn(true);
      } else {
        // logged out
        setIsLoggedIn(false);
      }
      setInit(true);
    });
  }, [])

 

그리고 로그인, 계정생성을 모두 하기 위해서 toggle버튼을 생성한다. 

// Auth.js

const [newAccount, setNewAccount] = useState(true);

const toggleAccount = () => setNewAccount((prev) => !prev);

return (
<span onClick={toggleAccount}>{newAccount ? "Log in " : "Create Account"}</span>
)

로그인을 하기 위해선 newAccount 값을 false, 계정 생성을 하기 위해선 newAccount 값을 true로 변경. 

 

 

Social Login

firebase/auth의 signInWIthPopup 함수를 사용한다. 이때 필요한 파라미터는 auth값과, provider가 필요한데, platform마다 다른 provider를 사용하기 때문에, 각각 provider객체를 새로 생성해 준다.

 

// Auth.js

const onSocialClick = async(event) => {
    const {
        target:{name},
    } = event;
    let provider;
    const auth = getAuth();
    if(name === 'google') {
        provider = new GoogleAuthProvider();
    } else if(name === 'github') {
        provider = new GithubAuthProvider();
    }
    await signInWithPopup(auth, provider);
}

return(
<button onClick={onSocialClick} name="google">Continue with Google</button>
<button onClick={onSocialClick} name="github">Continue with Github</button>
)

 

popup창이 뜨면서 로그인 하기

 

Logout 

profile 화면을 추가하고, Navigation 컴포넌트를 추가한다. 

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

Link 컴포넌트를 사용하여 해당 url로 이동시켜주는 링크를 보여준다.

 

Profile 

(<Route path="/profile" element={<Profile />}/>)

Router에 profile을 렌더링하는 Route도 추가한다.

 

const Profile = () => {
    const auth = getAuth();
    const navigate = useNavigate();
    const onLogOutClick = () => {
        signOut(auth);
        navigate('/');
    }
    return <>
        <button onClick={onLogOutClick}>Log Out</button>
    </>
}

로그아웃 버튼을 프로파일 컴포넌트에 추가하며, useNavigate를 사용하여 Log Out 버튼을 클릭했을 때 onClick함수로 signOut() 함수가 실행되고, "/" 홈 화면으로 다시 redirect가 되게 한다.

 

 

반응형