목표:
구글을 통한 소셜 로그인 방법은 간단하지만 내 코드에 어떻게 녹여낼지 화면에 표현될 흐름 등을 생각해서 다시 만들어보아야 했다.
과정:
초기에 만든 코드:
1. firebase 초기설정, 팝업창 로그인 함수
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { getAnalytics } from "firebase/analytics";
import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: "AIzaSyA_6Jaj9NVcAaxueyoCEvYGnWUxsoPf2tI",
authDomain: "easylogin-98763.firebaseapp.com",
projectId: "easylogin-98763",
storageBucket: "easylogin-98763.appspot.com",
messagingSenderId: "783928541301",
appId: "1:783928541301:web:0d0cb9645b1fc3965a783c",
measurementId: "G-RS5ES26W0B"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const analytics = getAnalytics(app);
const provider = new GoogleAuthProvider();
const auth = getAuth();
//팝업창 로그인 함수
const signInWithGoogle = () =>{
return signInWithPopup(auth, provider)
.then((result) => {
// This gives you a Google Access Token. You can use it to access the Google API.
const credential = GoogleAuthProvider.credentialFromResult(result);
const token = credential.accessToken;
// The signed-in user info.
const user = result.user;
console.log(result);
**이 부분에 토큰을 로컬 스토리지에 저장하고
로그인에 성공하였다는 창을 띄워준다. **
localStorage.setItem("access_token", token)
window.alert("회원가입에 성공하였습니다.");
// IdP data available using getAdditionalUserInfo(result)
// ...
}).catch((error) => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
// The email of the user's account used.
const email = error.customData.email;
// The AuthCredential type that was used.
const credential = GoogleAuthProvider.credentialFromError(error);
// ...
console.log(error);
window.alert("소셜로그인에 실패. 일반로그인을 해주세요")
});
};
export { signInWithGoogle}
import React, { useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import styled from "styled-components";
import login from "../../assets/img/login/login.png";
import devicon_google from "../../assets/img/login/devicon_google.png";
import kakao from "../../assets/img/login/kakao.png";
import { useDispatch } from "react-redux";
import { authActionCreator } from "../../redux/thunks/authThunk";
import { signInWithGoogle } from "../../api/socialAuthApi";
const Login = () => {
const [userId, setUserId] = useState("");
const [password, setPassword] = useState("");
const navigate = useNavigate();
const dispatch = useDispatch();
const handleInputChange = (e) => {
if (e.target.name === "email") {
setUserId(e.target.value);
} else if (e.target.name === "password") {
setPassword(e.target.value);
}
};
const handleSubmit = (e) => {
e.preventDefault();
dispatch(authActionCreator(userId, password));
navigate("/")
};
**
const googleLogin = () =>{
console.log('구글 버튼이 눌렸다.')
signInWithGoogle();
console.log('구글 로그인 팝업창 실행');
navigate('/');
**
이 부분이 문제가 되었다.
따라서 다음과 같이 실행해보았다.
**
const accessToken = localStorage.getItem
("access_token", token);
if(accessToken){
navigate("/")
};
**
이 역시 1)버튼이 눌리고 2)signInWithGoogle();
가 실행됨에 따라 모두 동시에 !!!!!! 실행되었다.
};
return (
<Container>
<div className="cover-img">
<img src={login} alt="login" height="100%" width="720px" />
</div>
<div className="loginPage">
<div className="loginPage-content">
<h1>로그인</h1>
<p>오늘도 좋은 날이에요</p>
<div className="form-container">
<div className="textfield-container">
<input
type="text"
value={userId}
name="email"
id=""
placeholder="이메일"
onChange={handleInputChange}
/>
<input
type="password"
value={password}
name="password"
placeholder="비밀번호"
onChange={handleInputChange}
/>
</div>
<div className="button-container">
<div className="checkbox">
<input type="checkbox" id="checkbox" />
로그인 정보 기억하기
</div>
<div className="button">
<button onClick={handleSubmit}>로그인</button>
</div>
</div>
</div>
<div className="password-container">
<p>비밀번호를 잊으셨나요?</p>
</div>
<div className="line">
<hr className="line" />
<p>Or</p>
<hr className="line" />
</div>
<div className="social-login">
<img src={devicon_google} alt="google" onClick={googleLogin} />
<img src={kakao} alt="kakao" />
</div>
<div className="signup-container">
<h3>
아이디가 없으신가요?{" "}
<h6>
<Link to="/signup">회원가입하기</Link>
</h6>
</h3>
</div>
</div>
</div>
</Container>
);
};
export default Login;
이슈:
구글 함수가 실행되기도 전에 화면이 초기메인으로
돌아가버린다. 팝업창으로 구글 로그인이 뜨고 메인화면은 로그인이 완료되기 전에 naviagate('/')가 실행되어버렸다. 이는 버튼이 눌리면서 모든 함수가 동시에 호출되기 때문이었다.
해결방법:
첫번째 방법) 버튼이 눌리면서 동시에가 아닌 순서를 보장받으면 실행되게 하는 비동기코드를 만들 수 있다.
두번째 방법) 구글에서 코드를 가져오면 자바스크립트 함수를 선언하게 된다. 함수 호출 부분이 아닌 구글이 제공한 함수를 선언하는 부분을 리액트형 컴포넌트로 바꾸어 마지막에 navigate('/')를 사용한다.
첫번째 방법으로 수정되어 완성 된 부분:
두번째 방법으로 함수 선언에 마지막에 navigate('/')를 써줄 시에 다른 컴포넌트에서 재사용하지 못할 가능성을 염두해 호출 부분의 코드를 바꾸기로 하였다.
const googleLogin = async() =>{
console.log('구글 버튼이 눌렸다.')
try{
await signInWithGoogle();
console.log('구글 로그인 팝업창실행')
navigate('/')
}catch(e){
console.log(e)
}
promise와 .then().catch()를 사용한 부분
const googleLogin = () =>{
signInWithGoogle()
.then((result)=>{
console.log('콜백함수가 실행되었다.', result);
navigate('/');
})
.catch((e)=>console.e('로그인실패',e));
console.log('버튼이 눌렸당!!')
}