[firebase] Firebase 이메일 중복확인
일단 이름 짱 긴 함수 보고 가시죠.
import {
getFirestore,
addDoc,
collection,
query,
where,
getDocs,
} from "firebase/firestore";
// config 생략
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
// 이메일 중복확인
export const checkDuplicateEmailWithFirebase = async (email) => {
try {
// db 중복 확인
const q = query(
collection(db, "users"),
where("email", "==", "db2@db.com")
);
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
console.log(doc.id, " => ", doc.data());
});
} catch (error) {
console.log("email::", error);
}
};
이 함수는 src/common/api/firebase.js 에 위치해있다.
물론 어디 위치에 있든 마음대로다,,,
(예전에 블로그 보다보면 내용은 있어도 어디에 써야할지 몰라서 곤란했던 적이 많아서 써봅니다..)
나는 이메일 중복 확인을 위해 가져왔지만!
firebase firestore에서 데이터를 가져오는 방법이다.
collection(db, {컬렉션 이름}),
where({찾을 필드}, "==", {찾을 내용})
즉 코드의 뜻은, users라는 컬렉션에서 email이 "db2@db.com"인 문서 찾아줘~ 임!!!
있으면 콘솔에 이렇게 예쁘게 찍힙니다요.
여기서 where() 생략하면 모든 문서를 찍어볼 수 있다.
근데,,, 그런 문서가 존재하지 않는다면??
error로 가거나 할 줄 알았는데 아무반응이 없었다.
그래서,,, chatGPT에게 물어봤습니다.
console.log(querySnapshot.empty)하면 true나 false가 나온다.
// 이메일 중복확인
export const checkDuplicateEmailWithFirebase = async (email) => {
console.log(email);
try {
// db 중복 확인
const q = query(
collection(db, "users"),
where("email", "==", "db2@db.com")
);
console.log(q);
const querySnapshot = await getDocs(q);
console.log(querySnapshot.empty);
return querySnapshot.empty ? false : true;
} catch (error) {
console.log("check email", error);
}
};
비어있으면? -> 중복이 아님! 그래서 false를 보내기로 했다.
!querySnapshot.empty 해도 될 것이다.
const checkDuplicateEmail = () => {
const email = getValues().email;
const isDuplicated = checkDuplicateEmailWithFirebase(email);
// true : 중복, false : 통과! \
console.log(isDuplicated);
};
함수를 갖다쓰는 부분에선 이렇게 쓴다.
근데 아무리봐도 함수 이름이 너무 긴데 ㅋㅋㅋ
이제 이 변수를 state에 저장하든가 해서 지지고볶고 하면 되겠지,,,
헉 이거 완전 ㄹㅅ님 말투네
useEffect(() => {
const email = getValues().email;
const isDuplicated = checkDuplicateEmailWithFirebase(email);
// true : 중복, false : 통과!
console.log("isDU", isDuplicated);
if (isDuplicated) {
setError("email", {
type: "custom",
message: "중복된 이메일입니다.",
});
}
}, [getValues().email]);
스키마에서... 함수를 가져와서 쓰기가 왠지 거부감이 느껴져서(?)
useEffect로 했는데, isDuplicated에 Object가 들어온다!
또 chatGPT에게 물어보았다.
checkDuplicateEmailWithFirebase 함수는 async 함수이므로 해당 함수를 호출하면 프로미스(promise)가 반환됩니다. 따라서 isDuplicated 변수에는 프로미스 객체가 저장되며, console.log를 통해 출력하면 프로미스 객체가 보이게 됩니다.
useEffect 함수는 비동기 함수를 직접 호출할 수 없으므로, async/await 구문을 사용하여 checkDuplicateEmailWithFirebase 함수를 호출해야 합니다. 이때, useEffect 함수에는 콜백 함수 내에서 async 키워드를 사용할 수 없습니다. 대신, 콜백 함수 내부에서 비동기 함수를 호출하고, 해당 함수의 반환 값을 처리하는 방식으로 해결할 수 있습니다.
useEffect(() => {
const checkEmailDuplicate = async () => {
const email = getValues().email;
try {
const isDuplicated = await checkDuplicateEmailWithFirebase(email);
console.log("isDuplicated", isDuplicated);
if (isDuplicated) {
setError("email", {
type: "custom",
message: "중복된 이메일입니다.",
});
}
} catch (error) {
console.log("check email", error);
}
};
checkEmailDuplicate();
}, [getValues().email]);
쓰고 싶으면 이렇게 쓰면 되겠다.
나는 스키마 파일로 옮겼다..
import * as yup from "yup";
import { checkDuplicateEmailWithFirebase } from "../api/firebase";
// 이메일 중복확인
export const checkDuplicateEmailWithYup = async (email) => {
try {
try {
const isDuplicated = checkDuplicateEmailWithFirebase(email);
return isDuplicated;
} catch (error) {
console.log(error);
}
} catch (error) {
// 유효성 검사 실패 시 에러 처리
console.log("check email", error);
throw error.message;
}
};
export const signUpSchema = yup.object({
phoneNumber: yup.string().required("필수 입력 항목입니다."),
email: yup
.string()
.required("필수 입력 항목입니다.")
.test("check-email", "중복된 이메일입니다.", async function (value) {
return !(await checkDuplicateEmailWithYup(value));
})
.matches(
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
"올바르지 않은 이메일 형식입니다."
),
password: yup
.string()
.matches(
/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d~!@#$%^&*()_+\-=\[\]{};':"<>?,./\\]{8,}$/,
"영문, 숫자를 포함해 최소 8자를 입력해주세요."
)
.required("필수 입력 항목입니다."),
confirmPassword: yup
.string()
.oneOf([yup.ref("password"), null], "비밀번호가 일치하지 않습니다.")
.required("필수 입력 항목입니다."),
nickname: yup
.string()
.matches(
/^[a-zA-Z가-힣]{1,8}$/,
"한글, 영문만 사용하여 최대 8자까지 가능합니다."
)
.max(8)
.required("필수 입력 항목입니다."),
});
export const signInSchema = yup.object({
email: yup.string().required("아이디를 입력해주세요."),
password: yup.string().required("비밀번호를 입력해주세요."),
});
.test("check-email", "중복된 이메일입니다.", async function (value) {
return !(await checkDuplicateEmailWithYup(value));
})
이렇게 체크하면 된다.
근데 아직 한 번 제출하기도 전에 빨간색으로 뜨는 게 약간... 거슬려요.
const {
control,
handleSubmit,
getValues,
formState: { errors, isSubmitted, isSubmitting },
} = useForm({
resolver: yupResolver(signUpSchema),
defaultValues: {
phoneNumber: "",
email: "",
password: "",
confirmPassword: "",
nickname: "",
},
mode: "onChange",
});
isSubmitted를 가져와서 (한 번 제출하면 true가 된다)
<Text
className={`text-[12px] ${
isSubmitted ? "text-red-600" : "text-gray-400"
}`}
>
그럼 한 번 제출하기 전까진 gray로 뜬다!