언어/Next.js

[Next 고캠핑] 파이어베이스 중복 오류, 회원가입

홍시_코딩기록 2024. 8. 12. 23:25

회원가입

[Firebase] Firebase App named '[DEFAULT]' already exists with different options or config (app/duplicate-app).

- 파이어베이스 설정을 하고 작업을 진행하려 하니 오류가 나왔다. 

찾아보니 앱을 중복해서 초기화하는 문제가 발생할 수 있다고 한다.

파이어베이스 앱이 있는지 확인하고 없을 때 새로 초기화 하는 방식으로 해야한다고 해서 수정을 했다.

파이어베이스 중복 오류

src > firebase > firebase.ts

import { getApp, getApps, initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_STORAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_MESSAGING_ID,
  appId: process.env.NEXT_PUBLIC_APP_ID,
};

// Initialize Firebase
// const app = initializeApp(firebaseConfig); //기존 코드

const app = !getApps().length ? initializeApp(firebaseConfig) : getApp();

export const auth = getAuth(app);

 

회원가입

components > login > formJoin.tsx

  const onSubmit = async (e: React.ChangeEvent<HTMLFormElement>) => {
    e.preventDefault();

    if (!emailRegex.test(email)) {
      setError("이메일 형식이 올바르지 않습니다.");
      setFormError(true);
    } else if (password?.length < 8) {
      setError("비밀번호는 8자리 이상으로 입력해주세요.");
      setFormError(true);
    } else if (password.length > 0 && password !== passwordConfirm) {
      setError("비밀번호와 비밀번호 확인 값이 다릅니다.");
      setFormError(true);
    } else {
      setError("");
      setFormError(false);
      await register(email, password);
      openModal("completed");
    }
  };

- 이메일 정규식은 블로그를 참고해서 썼다.

  • /^ : 시작
  • $/ : 끝
  • [A-Za-z0-9] : 영문 대소문자 혹은 숫자로 시작
  • ([-_.][A-Za-z0-9]) : 두 번째 글자부터는 영문 대소문자 혹은 숫자이며 - _ .이 들어갈 수 있음
  • * : 문자 또는 숫자가 0개 이상 나타남
  • @가 중간에 반드시 들어가야 함
  • 도메인 부분도 마찬가지로 영문 대소문자 혹은 숫자로 시작하며 그 다음부터-_.이 들어갈 수 있음
  • . 이 최소한 하나는 반드시 들어가야 함
  • .뒤에 com과 같은 최상위 도메인이 들어갈 자리 2-3자리 지정
  • + 참고) i : 전체에 대해서 대소문자를 구분하지 않음

- 이메일, 비밀번호가 맞지 않으면 오류메세지를 출력해야하기 때문에 setError에 메세지를 적어주고

- setFormError는 에러 상태를 부모 컴포넌트에 전달해서 css로 스타일을 주고 싶어서 추가하였다.

- 조건이 다 맞으면 등록이 되고 모달창을 띄운다.

 

 

  // 모달 닫고 새로고침
  const closeModal = () => {
    router.back();
    setTimeout(() => {
      router.reload();
    }, 300);
  };

- 모달 커스텀훅의 기존 closeModal을 사용하지 않고 새로고침을 추가하기 위해 새로 작성하였다.

 

 

회원가입 완료

 

 

** 수정 **

회원가입을 하고 로그인창으로 이동시키려 했지만 

파이어베이스는 회원가입을 하면 자동으로 로그인이 된다...

상황에 맞게 코드를 바꿨다.

 

const getUserId = () => ({
    email: emailInput.current?.value ?? "",
    password: pwdInput.current?.value ?? "",
    passwordConfirm: pwdConfirmInput.current?.value ?? "",
  });

  const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const { email, password, passwordConfirm } = getUserId();

    if (!emailRegex.test(email)) {
      setError("이메일 형식이 올바르지 않습니다.");
      setFormError(true);
    } else if (password?.length < 8) {
      setError("비밀번호는 8자리 이상으로 입력해주세요.");
      setFormError(true);
    } else if (password.length > 0 && password !== passwordConfirm) {
      setError("비밀번호와 비밀번호 확인 값이 다릅니다.");
      setFormError(true);
    } else {
      setError("");
      setFormError(false);
      openModal("completed");
    }
  };

  const closeModal = async () => {
    const { email, password } = getUserId();
    try {
      await register(email, password);
    } catch (error) {
      console.log(error);
      setError("회원가입 중 문제가 발생했습니다.");
    }
  };

- ref로 input의 값을 가져온다.

- onSubmit 이벤트에서 register를 하지 않고 모달 모달 띄우기까지만 한 뒤

 closeModal 이벤트에서 register()를 해주었다.

 링크 이동 이벤트가 없는 것은 login 화면에서 로그인이 된 상태에서 /login으로 접근하면 /홈화면으로 이동하게 했기 때문,,

 

 

전체코드

더보기

 

export default function FormJoin({
  setFormError,
}: {
  setFormError: (value: boolean) => void;
}) {
  const emailInput = useRef<HTMLInputElement>(null);
  const pwdInput = useRef<HTMLInputElement>(null);
  const pwdConfirmInput = useRef<HTMLInputElement>(null);
  const [error, setError] = useState<string>("");
  const { currentModal, openModal } = useModal();

  const emailRegex =
    /^[A-Za-z0-9]([-_.]?[A-Za-z0-9])*@[A-Za-z0-9]([-_.]?[A-Za-z0-9])*\.[A-Za-z]{2,3}$/i;

  async function register(email: string, password: string) {
    try {
      return await createUserWithEmailAndPassword(auth, email, password);
    } catch (error) {
      console.log(error);
    }
  }

  const getUserId = () => ({
    email: emailInput.current?.value ?? "",
    password: pwdInput.current?.value ?? "",
    passwordConfirm: pwdConfirmInput.current?.value ?? "",
  });

  const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const { email, password, passwordConfirm } = getUserId();

    if (!emailRegex.test(email)) {
      setError("이메일 형식이 올바르지 않습니다.");
      setFormError(true);
    } else if (password?.length < 8) {
      setError("비밀번호는 8자리 이상으로 입력해주세요.");
      setFormError(true);
    } else if (password.length > 0 && password !== passwordConfirm) {
      setError("비밀번호와 비밀번호 확인 값이 다릅니다.");
      setFormError(true);
    } else {
      setError("");
      setFormError(false);
      openModal("completed");
    }
  };

  const closeModal = async () => {
    const { email, password } = getUserId();
    try {
      await register(email, password);
    } catch (error) {
      console.log(error);
      setError("회원가입 중 문제가 발생했습니다.");
    }
  };

  return (
    <Form onSubmit={onSubmit}>
      <p>Email</p>
      <input
        name="email"
        type="email"
        placeholder="이메일을 입력해주세요."
        required
        ref={emailInput}
      />
      <p className="pwd">Password</p>
      <input
        name="password"
        type="password"
        placeholder="비밀번호를 입력해주세요."
        required
        ref={pwdInput}
      />
      <input
        name="passwordConfirm"
        type="password"
        placeholder="비밀번호를 다시 입력해주세요."
        required
        ref={pwdConfirmInput}
      />
      {error && <p className="error">{error}</p>}
      <input className="btn" type="submit" value="Sign Up" />

      {currentModal === "completed" && (
        <Modal
          currentModal={currentModal}
          hide={closeModal}
          message="회원가입이 완료되었습니다."
          subMessage="자동으로 로그인이 됩니다."
          type="info"
        />
      )}
    </Form>
  );
}

 

 

 

 

 

 

 

 

https://velog.io/@gkfla668/Firebase-Firebase-App-named-DEFAULT-already-exists-with-different-options-or-config-appduplicate-app

https://velog.io/@konveloper/Firebase-React-%EC%9D%B4%EB%A9%94%EC%9D%BC-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84

https://velog.io/@isabel_noh/React-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%9D%B4%EB%A9%94%EC%9D%BC-%EB%B0%8F-%EB%B9%84%EB%B0%80%EB%B2%88%ED%98%B8-%EC%A0%95%EA%B7%9C%EC%8B%9D