[React] 트위터 클론 (+ Firebase) - Auth

jjjjj·2022년 9월 29일
0

트위터 클론

목록 보기
2/6

👀 깃허브 링크
😎 클론 사이트 바로가기


⚠ 아직 부족한 점이 많아 정보 및 코드가 올바르지 않을 수 있습니다. 이 점 양해 부탁드리며 수정이 필요한 부분은 피드백 주시면 감사하겠습니다!

이슈가 있었던 부분은 제목 옆에 ❗를 붙였습니다.


➕ 기능 및 특징

  • 회원가입/로그인
    • 토글 버튼으로 회원가입/로그인을 따로 노출
    • 일반 이메일 형식이 아닌 구글, 깃허브 아이디로도 가입 가능
    • 사이트에 들어왔을 때 유저의 상태 변화 추적 가능
      • 로그인, 로그아웃, 어플리케이션 초기화(새로고침 or 재시작) 시 변화 추적
    • 구글, 깃허브가 아닌 일반 이메일 형식으로 회원가입/로그인 할 때 발생하는 에러 문구를includesreplace 메소드를 이용하여 표기


✨ 회원가입/로그인

└ 토글 버튼

// 코드 생략

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

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

{newAccount ? (
  <div className={styled.auth__notice}>
    <span>계정이 없으신가요?</span>
    <div>
      <span onClick={toggleAccount} className={styled.authSwitch}>
      가입
      </span>
      <span>하기</span>
    </div>
  </div>
) : (
  <div className={styled.auth__notice}>
    <span>이미 Nwitter에 가입하셨나요?</span>
    <div>
      <span onClick={toggleAccount} className={styled.authSwitch}>
        로그인
      </span>
      <span>하기</span>
    </div>
  </div>
)}

└ 구글, 깃허브

// 깃허브와 코드 같음

export const GoogleBtn = ({ newAccount }) => {
  const dispatch = useDispatch();
  const history = useHistory();

  const onSocialClick = async (e) => {
    let provider;
    let user;
    provider = new GoogleAuthProvider();
    try {
      await signInWithPopup(authService, provider).then(async (result) => {
        const credential = GoogleAuthProvider.credentialFromResult(result);
        const token = credential.accessToken;
        user = result.user;

        const docRef = doc(dbService, "users", user.email);
        await getDoc(docRef).then(async (docSnap) => {
          if (docSnap.exists()) {
            dispatch(setLoginToken("login"));
            dispatch(
              setCurrentUser({
                ...docSnap.data(),
              })
            );
          } else {
            const usersRef = collection(dbService, "users");
            await setDoc(doc(usersRef, user.email), {
              uid: user.uid,
              displayName: user.email.split("@")[0],
              email: user.email,
              photoURL: noneProfile,
              createdAtId: Date.now(),
              description: "",
              bgURL: bgimg,
              bookmark: [],
              followAt: [],
              follower: [],
              following: [],
              reNweet: [],
              token: token,
            });
            dispatch(setLoginToken("login"));
            dispatch(
              setCurrentUser({
                uid: user.uid,
                displayName: user.email.split("@")[0],
                email: user.email,
                photoURL: noneProfile,
                bgURL: bgimg,
                description: "",
                createdAtId: Date.now(),
                bookmark: [],
                followAt: [],
                follower: [],
                following: [],
                reNweet: [],
              })
            );
          }
        });
      });
      history.push("/");
    } catch (error) {
      console.log(error);
      alert("Google 로그인 오류");
    }
  };

  return (
    <button onClick={onSocialClick} name="google" className={styled.authBtn}>
      <FcGoogle />
      {newAccount ? "Google로 로그인 하기" : "Google로 가입하기"}
    </button>
  );
};

└ 유저 상태 변화 추적

const [init, setInit] = useState(false);
const [userObj, setUserObj] = useState(null);

useEffect(() => {
  // 유저 상태 변화 추적(로그인, 로그아웃, 어플리케이션 초기화 시)
  authService.onAuthStateChanged(async (user) => {
    if (user) {
      setUserObj(user);
    } else {
      setUserObj(null);
    }
    setInit(true); // 어플리케이션이 언제 시작해도 onAuthStateChanged가 실행돼야 하기 때문에 true
  });
}, []);

return (
  <>
    {init ? (
      <AppRouters isLoggedIn={Boolean(userObj)} userObj={userObj}/>
    ) : (
      <div className={styled.render__loading}>
        <AiOutlineTwitter className={styled.render__logo} />
      </div>
    )}
  </>
);

└ 에러 문구

// 코드 생략

const errorMessages = {
  "(auth/email-already-in-use).": "이미 가입이 되어있는 이메일입니다.",
  "(auth/invalid-email).": "올바르지 않은 이메일 형식입니다.",
  "(auth/weak-password)": "비밀번호를 최소 6글자 이상 입력해주세요.",
  "(auth/wrong-password).": "이메일이나 비밀번호가 틀립니다.",
  "(auth/too-many-requests)":
  "로그인 시도가 여러 번 실패하여 이 계정에 대한 액세스가 일시적으로 비활성화되었습니다. 비밀번호를 재설정하여 즉시 복원하거나 나중에 다시 시도할 수 있습니다.",
  "(auth/user-not-found)": "가입된 아이디를 찾을 수 없습니다.",
};

// ... 생략
} catch (error) {
  const errorKey = Object.keys(errorMessages).find((key) =>
    error.message.includes(key)
  );
  const errorMessage = errorKey ? errorMessages[errorKey] : error.message;
  setError(errorMessage);
}
profile
의미있게 하기~.~

0개의 댓글