파이어베이스에서 깃허브 인증 사용설정하는 방법은 이 글에 자세히 작성하였다.
import React from "react";
import { provider } from "../../../firebaseConfig";
import { getAuth, signInWithPopup } from "firebase/auth";
function Auth() {
const onClickLoginBtn = async () => {
const auth = getAuth();
signInWithPopup(auth, provider)
.catch((error) => {
console.log(error.message);
});
}
return (
<>
<div onClick={onClickLoginBtn}>로그인하기</div>
</>
)
}
export default Auth;
로그인하기 버튼을 누르면 onClickLoginBtn 함수가 실행되며 signInWithPopup을 통해 로그인 처리가 된다.
import React, { useEffect, useState } from "react";
import { BrowserRouter } from "react-router-dom";
import Auth from "./pages/auth";
import Main from "./pages/main";
import { getAuth, onAuthStateChanged } from "firebase/auth";
function Router() {
const [isLogin, setIsLogin] = useState(false);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const auth = getAuth();
onAuthStateChanged(auth, (user) => {
if (user) {
console.log(user); // console.log
setIsLogin(true);
setIsLoading(false);
} else {
alert('로그인 해주세요');
setIsLogin(false);
setIsLoading(false);
}
});
}, []);
return (
<BrowserRouter>
{isLoading ? 'loading...' : isLogin ? <Main userInfoData={userInfoData} /> : <Auth />}
</BrowserRouter>
);
};
export default Router;
useEffect를 통해 렌더링될때마다 onAuthStateChanged함수로 로그인 여부를 파악하고, 로그인 여부에따라 Auth, Main컴포넌트가 다르게 화면에 뜨게된다.
import React from "react";
import { getAuth, signOut } from "firebase/auth";
function Main() {
const onClickLogoutBtn = () => {
const auth = getAuth();
signOut(auth).then(() => {
alert('로그아웃 되었습니다.');
}).catch((error) => {
console.log(error);
alert(error);
});
}
return (
<div className="LogoutBtn" onClick={onClickLogoutBtn}>로그아웃하기</div>
);
}
초기 구상에서 유저들을 검색하여 친구 추가를 할 수 있도록 구상했는데, 검색하려면 우선 유저 정보를 데이터베이스에 저장할 필요가 있었다. 그래서 로그인시 유저 정보를 저장하는 로직을 구현하였다.
import React from "react";
import { provider, db } from "../../../firebaseConfig";
import { getAuth, signInWithPopup } from "firebase/auth";
import { doc, setDoc } from "firebase/firestore";
function Auth() {
const onClickLoginBtn = async () => {
const auth = getAuth();
signInWithPopup(auth, provider)
.then(async (result) => {
const { uid, displayName, photoURL } = result.user;
await setDoc(doc(db, "Users", `${uid}`), {
uid: `${uid}`,
userName: `${displayName}`,
photoURL: `${photoURL}`
});
...
로그인시 result에서 필요한 유저 정보를 가져와 선언한 후, "Users" Doc에 유저 컬렉션을 생성하여 정보를 객체형태로 저장한다.
...
export interface UserData {
uid?: string;
userName?: string;
photoURL?: string;
}
function Main({userInfoData}: {userInfoData: UserData}) {
const [findUser, setFindUser] = useState<string>('');
const [userData, setUserData] = useState<Array<UserData>>([]);
const [isFindUserFinished, setIsFindUserFinished] = useState<boolean>(false);
// 유저검색
const onChangeFindUserInput = (e: React.FormEvent<HTMLInputElement>) => {
const { value } = e.target as HTMLInputElement;
setFindUser(value);
}
const onSubmitFindUser = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const q = query(collection(db, "Users"), where("userName", "==", findUser));
const querySnapshot = await getDocs(q);
setUserData([]); // 초기화시키고 forEach문 동작(중복방지)
querySnapshot.forEach((doc) => {
const {userName, photoURL, uid} = doc.data();
const data: UserData = {uid, userName, photoURL};
setUserData(arr => arr ? [...arr, data] : [data]);
});
setIsFindUserFinished(true);
}
return (
<>
<div>
<form onSubmit={onSubmitFindUser}>
<div className="FindUserInputBox">
<input className="FindUserInput"
value={findUser}
onChange={onChangeFindUserInput}
type="text"
placeholder="유저를 검색하세요"
/>
<button type="submit">
<SearchIcon className="FindUserInputIcon" />
</button>
</div>
</form>
</div>
<div>
{userData.length || !isFindUserFinished
? userData.map(data => <UserList key={data.uid} data={data}/>)
: '해당 유저정보를 찾을수없습니다.'}
</div>
...
</>
)
}
export default Main;
가져올 UserData의 타입을 선언하고, 검색한 이름이 일치하는 데이터를 조건문을 통해 firestore에서 가져온다. 가져온 데이터는 useState Hook을 이용해 setUserData로 리스트 형식으로 가져온 후, userData.map을 통해 유저정보를 화면에 표시한다.
문제 해결
forEach문으로 데이터를 가져올 때 검색을 계속 누르면 userData 배열에 결과값이 계속 추가되어 데이터가 중복되어 추가되는 문제가 있었다. 그래서 가져오기 전 배열을 초기화하도록 수정하였다.
유저 정보가 없으면 (빈 배열 [ ]) 유저 정보가 없다는 문구를 띄우는데, 검색하기 전에도 기본으로 빈 배열이기 때문에 항상 문구가 띄워진다는 문제점이 있었다. 이를 해결하기 위해 유저 검색이 끝났을때 true를 설정하는 훅을 작성하여 유저검색을 하지 않았을때는 아무 문구도 띄우지 않도록하는 논리식을 작성하여 추가하였다.
결과물