React Shopping Mall 정리

한대희·2023년 5월 18일
0
post-thumbnail

구현한 기능

  1. firebase 구글 로그인, 로그아웃
  2. admin사용자 설정
  3. 상품 등록
  4. 장바구니

핵심 기술

< 1. firebase 구글 로그인 >

  • 먼저 firebase를 사용하기 위해 설치를 먼저 해보자
    npm install firebase
  • 로그인 기능을 구현해 보기 위해 Fire Base를 셋업해 보자. 먼저 fire base의 프로젝트 설정에 들어가 거기에 나와 있는 코드를 복사해서 src폴더 안에 api라는 폴더를 만들 고 그아래 firebase.js파일을 만들어 여기다 복사해 보자.
    // src폴더안에 api폴더 안에 firebase.js파일
    // 불필요한 내용들은 삭제한 상태다.
    
    import { initializeApp } from "firebase/app";
    
    const firebaseConfig = {
      apiKey: "AIzaSyDrbqC7UbsTf9DC3vBEl9JMhv--G3-V7B0",
      authDomain: "shopping-5c758.firebaseapp.com",
      databaseURL: "https://shopping-5c758-default-rtdb.asia-southeast1.firebasedatabase.app",
      projectId: "shopping-5c758",
    
    };
    
    // Initialize Firebase
    const app = initializeApp(firebaseConfig);
    
  • 그런데 이러한 secret key들을 대놓고 이렇게 파일에 올려두거나 하면 모르고 commit을 하거나 했을 때 이게 모두 공개되어 버리기 때문에 git.ignore파일에 보면 env.local이라고 되어 있는데, git이 이 코드를 무시하기 위해 env.local파일을 하나 만들어서 여기다 넣어줘야 한다.
    // env.local이라는 파일이고 왼쪽 처럼 네이밍을 해서 위의 코드를 넣어준다.
    // REACT_APP_을 꼭 붙이고, 그 뒤에 원하는 이름을 작성하면 된다. 
    REACT_APP_FIREBASE_API_KEY=AIzaSyDrbqC7UbsTf9DC3vBEl9JMhv--G3-V7B0
    REACT_APP_FIREBASE_AUTH_DOMAIN=shopping-5c758.firebaseapp.com
    REACT_APP_FIREBASE_DB_URL=https://shopping-5c758-default-rtdb.asia-southeast1.firebasedatabase.app
    REACT_APP_FIREBASE_PROJECT_ID=shopping-5c758
  • 그 후 다시 firebase.js에 가서 아래처럼 수정을 해준다.
    import { initializeApp } from "firebase/app";
    
    const firebaseConfig = {
      apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
      authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
      databaseURL: process.env.REACT_APP_FIREBASE_DB_URL,
      projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
    
    };
    
    const app = initializeApp(firebaseConfig);
  • 그 다음 구글 로그인을 사용하기 위해 firebase에서 docs를 참조하여 코드를 아래 처럼 가져온다.
    import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";
    import { initializeApp } from "firebase/app";
    
    const firebaseConfig = {
      apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
      authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
      databaseURL: process.env.REACT_APP_FIREBASE_DB_URL,
      projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
    
    };
    
    const app = initializeApp(firebaseConfig);
    const auth = getAuth();
    const provider = new GoogleAuthProvider();
    
    export function login() {
        signInWithPopup(auth, provider)
          .then((result) => {
            const user = result.user;
            console.log(user)
          })
          .catch(console.error);
      }
  • 이제 로그인 버튼을 클릭하면 로그인 창이 나타날 것이고, 현재 코드에서 console에 user에 관한 정보를 나타나게 했으므로 개발자도구 console창에 가면 정보가 뜰 것이다.

< 2. Admin User >

  • 먼저 사용자가 로그인을 하면 고유한 uid 값을 얻을 수 있다.
  • firebase의 database에 가서 admins라는 배열을 만들고, 그 배열 안에 로그인한 사용자의 uid값을 넣어주면 된다.
  • 그러면 나중에 사용자가 로그인을 할 때 해당 uid값이 firebase의 데이터베이스의 admins라는 배열안에 들어 있는지 비교하면 해당 사용자가 어드민인지 아닌지 확인할 수 있을 것이다.
  • 자 그러면 데이터 베이스에서 admins라는 배열을 어떻게 가져 올 수 있을까? firebase의 Docs에서 Build에 들어가서 왼쪽 navbar에 보면 실시간 데이터베이스 항목이 있을 것이고, 그걸 클릭해서 들어가면 웹이라는 카테고리가 있을 거고, 거기에 들어가서 데이터를 불러올 것이므로 데이터 읽기 및 쓰기 항목에 들어가면 사용법이 나와 있다.
 import { getAuth, signInWithPopup, GoogleAuthProvider,signOut,onAuthStateChanged } from "firebase/auth";
 import { initializeApp } from "firebase/app";
 // docs에 나와 있는 대로 import를 하고
 import { getDatabase, ref, child, get, DataSnapshot } from "firebase/database";
 
 const firebaseConfig = {
   apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
   authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
   databaseURL: process.env.REACT_APP_FIREBASE_DB_URL,
   projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
 
 };
 
 const app = initializeApp(firebaseConfig);
 const auth = getAuth();
 const provider = new GoogleAuthProvider();
 
   export async function login() {
     return signInWithPopup(auth, provider)
       .then((result) => {
         const user = result.user;
         // console.log(user)
         return user
       })
       .catch(console.error);
   }
 
   export async function logout() {
     return signOut(auth).then(()=> null)
   }
 
 //아래에서 adminuser를 만들었고, adminuser는 비동기 함수 이기 때문에 여기도 async를 붙여 주고,
 // user가 true라면, 즉 로그인을 했다면 adminuser함수를 호출을 하는 코드를 작성해서 인자로 들어온 callback함수의
 // 인자로 넣어 준다.
   export function onUserStateChange(callback) {
     onAuthStateChanged(auth, async (user) => {
       const updatedUser = user ? adminuser(user) : null
 
       callback(updatedUser)
     });
   }
 
 //import한 getDatabase를 활용하여 데이터 베이스를 가져오고
   const database = getDatabase(app)
 // 그리고 adminuser함수를 만든다. adminuser함수는 firebase의 database에서 data를 가져온다 
 // 즉 네트워크 통신이 이루어지기 때문에 비동기 처리를 위해 async를 붙여 준다.
   async function adminuser(user) {
 // docs에 나와있는대로 ref를 활용하여 초기화된 database를 가져오고, 그 중 database에 들어
 // 있는 admins라는 배열을 가져올 것이다.그리고 데이터를 잘 가지고 왔다면 snapshot이 전달이 될
 //것이고,snapshot이 존재 한다면 val를 이용해서 snapshot에 있는 value를 가지고 와
 // admins라는 변수에 넣어 준다.
 // 그리고 isAdmin이라는 변수에는 로그인한 사용자의 uid값을 넣어서 할당해 주고
 // 최종적으로 adminuser함수의 인자로 들어온 user정보 객체 안에, isAdmin을 추가해 준다.
     return get(ref(database, 'admins'))//
 			.then((snapshot) => {
       if(snapshot.exists()) {
         const admins = snapshot.val()
         console.log(admins)
         const isAdmin = admins.includes(user.uid)
         return {...user, isAdmin}
       }
 // admin이라는 데이터가 존재하지 않거나 데이터를 잘 받아오지 못하였을 경우에는 그냥 User를 리턴한다.
       return user;
     })
   }
 ```
 
 ```jsx
 import React, { useState, useEffect } from 'react'
 import { Link } from 'react-router-dom'
 import {HiShoppingBag} from 'react-icons/hi'
 import {GiClothes} from 'react-icons/gi'
 import { login, logout, onUserStateChange } from "../api/firebase";
 import UserInfo from './UserInfo';
 
 export default function Navbar() {
   const [user, setUser] = useState()
   // console.log(user)
   const handleLogin = () => {
     login().then(user=> setUser(user))  
   }
   const handleLogout = () => {
     logout().then(user=> setUser(user))  
   }
 //firebase에서 로직을 구현을 했고, navbar에서 onUserStateChange를 호출할때 들어온 인자는 사용자가 admin이면 isAdmin이 true
 // 라는 것이 포함되어 전달이 될 것이고, 그걸 상태값으로 업데이트 해주면 어드민사용자로 로그인이 된걸 확인할 수 있다.
   useEffect(()=>{
     onUserStateChange((user) => {
       // console.log(user)
       setUser(user)
     })
   },[])
   return (
     <header className='flex justify-between border-b border-gray-300 p-2'>
       <Link to='/' className='flex items-center text-3xl text-logo'>
         <HiShoppingBag />
         <h1>뉴이어</h1>
       </Link>
       <nav className='flex items-center gap-4 font-semibold'>
         <Link to='/products'>상품</Link>
         <Link to='/carts'>장바구니</Link>
         <Link to='/products/new' className='text-2xl'>
           <GiClothes/>
         </Link>
         {user && <UserInfo user={user}/>}
         {!user && <button onClick={handleLogin}>Login</button>}
         {user && <button onClick={handleLogout}>LogOut</button>}
       </nav>
     </header>
   )
 }
 ```
코드를 입력하세요

개발자 도구를 살펴 보면 isAdmin이 true인 것을 확인해 볼 수 있다.

profile
개발 블로그

0개의 댓글