[Tistory] [Next 고캠핑] 로그인 상태관리, 로그아웃

원글 페이지 : 바로가기

로그인 페이지/ 로그인 시 전화면으로 이동/ 로그아웃시 로그인, 회원가입 화면 page > login
const [formError, setFormError] = useState(false); // 로그인, 회원가입 에러
const [tabLogin, setTabLogin] = useState(true); // 로그인, 회원가입 탭
const router = useRouter();
const { isLogin } = useAuth();

useEffect(() => {
// 로그인된 상태에서 /login 들어오면 홈으로
if (isLogin) {
void router.replace(“/”);
} else {
// active 클래스 1초 뒤 삭제
const timer = setTimeout(() => {
setFormError(false);
}, 1000);
return () => {
clearTimeout(timer);
};
}
}, [formError, isLogin]); (isLogin 하단 context API 코드 참고) – 로그인, 회원가입에서 setFormError가 넘어오면 클래스 active가 추가된다. 스타일을 위해서 1초뒤 삭제했다. – 로그인을 한 상태에서 로그인페이지에 다시 올 수 도 있으니 그때는 / 홈으로 이 로그인 컴포넌트 componentes > formLogin.tsx const emailInput = useRef(null);
const pwdInput = useRef(null);
const router = useRouter();

async function login(email: string, password: string) {
try {
const userLogin = await signInWithEmailAndPassword(auth, email, password);
setFormError(false);
router.back();
return userLogin;
} catch (error) {
console.log(error);
setFormError(true);
return null;
}
}

const onSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const email = emailInput.current?.value ?? “”;
const password = pwdInput.current?.value ?? “”;
await login(email, password);
}; – 로그인을 하면 이전 화면으로 이동 – onSubmit 여기서도 email, password는 ref로 input 값을 받아왔다. Warning: Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup – 원래 onSubmit에 router.back()을 했는데 오류가 나왔었다. 찾아보니 컴포넌트가 이미 언마운트되었는데도 상태를 업데이트하려고 하면 나온다고 한다. 그래서 페이지 이동을 login에서 진행되게 바꿔주었다. https://kyounghwan01.github.io/blog/React/cant-perform-a-React-state-update-on-an-unmounted-component/#%E1%84%87%E1%85%A1%E1%86%AF%E1%84%89%E1%85%A2%E1%86%BC-%E1%84%8B%E1%85%B5%E1%84%8B%E1%85%B2 로그아웃 export default function LayoutHeader({ className }: { className?: string }) {
const { isLogin } = useAuth();
const { currentModal, openModal, closeModal } = useModal();

// 로그아웃 클릭 이벤트
const onClickLogout = async () => {
try {
await signOut(auth);
openModal(“logout”);
} catch (error) {
console.log(error);
}
}; 헤더에 있는 로그아웃 버튼 – 버튼을 클릭하면 로그아웃이 되고 모달을 띄운다. 💡로그아웃 header.tsx 더보기 export default function LayoutHeader({ className }: { className?: string }) {
const isMobile = useIsMobile();
const [menuOpen, setMenuOpen] = useState(false);
const { isLogin } = useAuth();
const { currentModal, openModal, closeModal } = useModal();

// 로그아웃 클릭 이벤트
const onClickLogout = async () => {
try {
await signOut(auth);
openModal(“logout”);
} catch (error) {
console.log(error);
}
};

// 모바일 메뉴 토글 클릭이벤트
const onClickMenu = () => {
setMenuOpen((prev) => !prev);
};

return (
<>



요즘캠핑


{!isMobile ? (


  • 요즘 캠핑 후기

  • 내 캠핑장
  • {!isLogin ? (

    로그인

    ) : (

    )}

  • ) : (

  • {!isLogin ? (

    로그인

    ) : (

    )}



  • )}
    {/* 모바일메뉴 */}
    {isMobile && (

    )}
    {/* 후기, 내 캠핑장 alert */}
    {currentModal === “logout” && (

    )}



    );
    } 💡전체코드 formLogin.tsx 더보기 export default function FormLogin({
    formError,
    setFormError,
    }: {
    formError: boolean;
    setFormError: (value: boolean) => void;
    }) {
    const emailInput = useRef(null);
    const pwdInput = useRef(null);
    const router = useRouter();

    async function login(email: string, password: string) {
    try {
    const userLogin = await signInWithEmailAndPassword(auth, email, password);
    setFormError(false);
    router.back();
    return userLogin;
    } catch (error) {
    console.log(error);
    setFormError(true);
    return null;
    }
    }

    const onSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const email = emailInput.current?.value ?? “”;
    const password = pwdInput.current?.value ?? “”;
    await login(email, password);
    };
    return (

    Email

    Password


    {formError &&

    이메일, 비밀번호를 확인해주세요.

    }


    );
    } 💡 전체 코드 useAuth – 나는 우선 유저정보는 필요없고 로그인 상태만 필요해서 login이 됐는지 안됐는지만 확인하는 용도로 context를 만들었다. 더보기 import { auth } from “@/firebase/firebase”;
    import { onAuthStateChanged } from “firebase/auth”;
    import { createContext, useContext, useEffect, useState } from “react”;

    interface AuthContextType {
    isLogin: boolean;
    }

    export const AuthContext = createContext({
    isLogin: false,
    });

    export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
    const [isLogin, setIsLogin] = useState(false);

    useEffect(() => {
    onAuthStateChanged(auth, (user) => {
    if (user) {
    setIsLogin(true);
    } else {
    setIsLogin(false);
    }
    });
    }, [auth]);
    return (
    {children}
    );
    };

    export const useAuth = () => {
    const context = useContext(AuthContext);
    if (context === undefined) {
    throw new Error(“context가 없을 경우”);
    }
    return context;
    }; 💡 전체 코드 login 더보기 export default function index() {
    const [formError, setFormError] = useState(false);
    const [tabLogin, setTabLogin] = useState(true);
    const router = useRouter();
    const { isLogin } = useAuth();

    useEffect(() => {
    // 로그인된 상태에서 /login 들어오면 홈으로
    if (isLogin) {
    void router.replace(“/”);
    } else {
    // active 클래스 1초 뒤 삭제
    const timer = setTimeout(() => {
    setFormError(false);
    }, 1000);
    return () => {
    clearTimeout(timer);
    };
    }
    }, [formError, isLogin]);

    if (isLogin) {
    return null;
    }
    return (


    Welcome

    Daily Camping!

    캠핑 이미지



    홈 화면으로 돌아가기



    {/* 로그인/ 회원가입 탭 */}
    {tabLogin ? (

    Login

    아래 테스트 이메일로 로그인 가능합니다:)

    ) : (

    Sign Up

    회원가입 입니다:)

    )}




    );
    } 참고 블로그 https://velog.io/@jian09/Firebase-Auth-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC 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/@minz-cha/React-Firebase%EB%A5%BC-%ED%86%B5%ED%95%B4-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84

    답글 남기기

    이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다