저번 시간에 내가 만든 앱 호스팅하는 방법을 알아봤다.
이제부터는 구글 로그인, 이메일 로그인 이렇게 2가지를 구현 연습해보려고 한다.
이번 시간에는 firebase를 이용하여 구글 로그인을 구현한 과정을 포스팅하려고 한다.
저번 시간에 추가했던 learn-firebase 프로젝트 클릭 → 왼쪽에 authentication 클릭
시작하기 클릭!
나는 초보자이므로 구글 하나로만 우선 도전을 시작해본다.(비장) 구글 클릭!
사용설정 toggle button 클릭 → 프로젝트 지원 이메일에 나의 이메일 입력하기 → 저장
짜잔! 사용 설정되었다고 뜬다~~
좌측에 프로젝트 개요 옆에 톱니바퀴 → 프로젝트 설정 클릭!
스크롤을 내리면 내 앱 하단에
const firebaseConfig = {
.
.
.
.
.
const analytics = getAnalytics(app);
까지 코드 복사
src 내부에 service라는 폴더를 만들었다.
→ service 폴더 내부에 firebase.js를 만든다.
→ 루트 디렉토리에 .env 파일도 만든다. API key 등 github에 올라가면 안되는 정보들을 따로 저장하는 파일이다. 주의!! src폴더가 아닌 root 디렉토리에 있는지 2번 확인 3번 확인하자!!
REACT_APP_API_KEY=
REACT_APP_AUTH_DOMAIN=
REACT_APP_PROJECT_ID=
REACT_APP_STORAGE_BUCKET=
REACT_APP_MESSAGING_SENDER_ID=
REACT_APP_APP_ID=
REACT_APP_MEASUREMENT_ID=
뒤에 입력해서 env 파일에 저장하기!
여기까지는 아주 순조로워서 자신감 뿜뿜했다.
하지만.. docs 보면서 코드 작성하는 것부터는 크고 작은 난관에 부딪치는데..
쟈스민의 난관 극복 일기 시작합니다
이제 슬슬 코드 작성을 해볼까 룰룰루~?
처음에 나의 index.ts 파일에 코드들이 한데 모여있었다.
import React from "react";
import ReactDOM from "react-dom/client";
import { initializeApp } from "firebase/app";
import { getAnalytics } from "firebase/analytics";
import App from "./App";
import Join from "./SignUp";
import Router from "./Router";
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_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_APP_ID,
measurementId: process.env.REACT_APP_MEASUREMENT_ID,
};
initializeApp(firebaseConfig);
// const analytics = getAnalytics(app);
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<React.StrictMode>
<Router />
</React.StrictMode>
);
어휴 지저분해라
firebase.ts파일을 service 폴더에 만들어서 firebaseConfig를 따로 보관하려고 했다.
초기 삽질 유발 firebase.ts파일
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_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_APP_ID,
measurementId: process.env.REACT_APP_MEASUREMENT_ID,
};
const app = initializeApp(firebaseConfig);
const auth = getAuth();
export default{ app, auth };
뭔가 이상함을 감지하셨다면 당신은..
저의 스승님이 되어주십쇼..
App.ts에서
import { auth } from "./service/firebase";
빨간 줄이 마구 그어지기 시작하는 것이었다.
에러 내용은 이러하다.
Module '"./service/firebase"'has no exported member 'auth'. Did you mean to use 'import auth from "./service/firebase"' instead?
저 firebase.ts 마지막에 export default {app, auth} 했는데염?
그렇다. 여기가 문제였다.
ㅋㅋㅋㅋㅋㅋㅋㅋㅋ
export default와 export의 차이도 모르고 쓰고 있었다.
여기가 문제였는데 여기에 빨간줄이 그어지지 않아서 몇시간 동안 몰랐다.
이번 기회에 공부해본 차이를 간략하게 정리하자면,
export default
: 해당 모듈에 한 개의 개체(클래스, 함수, 변수)만 있을 때 사용한다. 즉 export default 개체명
요런 식으로 사용.
export
: 복수의 개체가 있을 때 여러 개를 export할 수 있다.
export {개체1, 개체2}
요런 식으로 사용.
참고: https://quark21.tistory.com/314
내 코드에서 app, auth 2가지를 내보내야 하므로 export {app, auth} 이런 식으로 쓰는게 맞는 것이었다.
그래도 이번 기회에 export default와 export를 구분해서 써야 한다는 소중한 렛쓴을 얻게되었다.
firebase.ts의 마지막 줄을
export { app, auth };
이렇게 고치니 더 이상 에러가 나지 않는다.
++ 또는 어차피 app을 export할 필요가 굳이 없다면 firebase.ts 마지막 줄에
export default auth;
이렇게 auth 한개만 export default하고
App.ts에서는 import 할 때
import auth from "./service/firebase";
이렇게 중괄호를 없애고 import 해도 에러가 사라진다.
난관 1 여차저차 극복 완료!
https://firebase.google.com/docs/auth/web/google-signin?hl=ko&authuser=0
분명히 .env 파일에 나의 소중한 API key를 넣어놨는데 invalid-api-key라는 것이다.
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_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_APP_ID,
measurementId: process.env.REACT_APP_MEASUREMENT_ID,
};
console.log("apiKey: ", firebaseConfig.apiKey);
// apiKey: undefined
.env파일이랑 번갈아가면서 한참 헤맸다.
블로그를 돌아다녀보니 .env파일은 반드시 루트 디렉토리에 있어야 한다고 한다. 내 .env는? src폴더에 있었네? 오호호호 참 쉽군 루트 디렉토리로 이동~
하지만 여전히
console.log("apiKey: ", firebaseConfig.apiKey);
// apiKey: undefined
apiKey는 정체를 드러내지 않는 것이었다.
그렇게 삽질 무한반복한지 2시간 후..
.
.
방사능 티셔츠 입고 허무함의 땐스
.env파일을 생성 후 다른 파일에서 불러오려면 vscode를 껐다 켜야만 된다고 한다.
응 오키~
좋았어 결심했어
나도 docs를 최우선으로 읽는 모범적인 개발자가 될테야
지금까지 docs 읽는 습관이 충분히 들여지지 못했다는 생각이 들었다.
그래서 docs를 계속 읽어봤는데.. 그랬는데..
이해가 잘 안갔다.
signInWithPopup함수를 사용하려고 하는데 기본적인 작동 원리에 대한 이해도 없이 시작해서 헤맸다.
처음에 작성을 시도했던 말도 안되는 코드
//🤣🤣🤣🤣🤣🤣
function App() {
const auth = getAuth();
const provider = new GoogleAuthProvider();
signInWithPopup(auth, provider)
.then((result) => {
const user = result.user;
}).catch((error) => {
console.log(error)
}
};
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 다시 보니까 재밌다 (당시에는 진지했다구)
함수를 사용하여 코드를 묶어주고 그 함수를 login button에 onClick함수로 들어가게끔 만들어야 되는 것이었다.
그렇게 헤매다가 겨우겨우 고친 코드
.
.
(생략)
.
.
function App() {
const [userData, setUserData] = useState(null) as any;
const handleGoogleLogin = () => {
// Google 제공업체 객체의 인스턴스를 생성
const provider = new GoogleAuthProvider();
signInWithPopup(auth, provider)
.then((result) => {
// user 정보를 setUserData를 이용하여 userData로 state 지정.
setUserData(result.user);
console.log(result);
const name = result.user.displayName;
console.log(name);
})
.catch((error) => {
console.log(error);
});
};
return (
<BtnWrapper className='App'>
{userData ? `${userData.displayName}님 환영합니다~` : null}
// Btn 컴포넌트에 onClick 함수로 handleGoogleLogin 지정.
<Btn onClick={handleGoogleLogin}>Google Login</Btn>
.
.
(생략)
.
.
handleGoogleLogin이라는 함수 내부에
이렇게 헤매고 해매다보니 결국 구글 로그인 구현 성공!!
npm run build
firebase deploy
처음 들어가서 로그인하기 전
Google Login 버튼을 누르면
popup 창이 뜨고
짜잔~ 로그인 성공!!
나의 소중한 앱
https://learn-firebase-2ebf6.web.app/
firebase.ts
App.ts
여기저기 바보같은 실수를 많이 했지만 ㅋㅋㅋㅋ 난관을 헤치고 구글 로그인 구현 목표를 달성하니 아주 뿌듯하다!!
그런데
const [userData, setUserData] = useState(null) as any;
state의 type을 설정할 때 우선 에러를 막아보려고 as any로 타입을 줬던 부분이 좀 아쉬운 것 같다.
typescript를 아직 깊게 알지 못해서 type을 어떻게 줘야할지 아직 잘 모르겠다. ㅠㅠ
typescript를 좀 더 공부해보고 나서 이부분은 꼭 다시 봐야겠다!
이제 로그아웃, 회원가입, 회원탈퇴 구현도 해봐야겠다 !
짜이찌앤~~
++멘토님도 입장 인증샷 보내주심! 뿌듯하다~~