[7/13 TIL]회원가입/로그인/로그아웃 페이지 전환 - 트러블 슈팅

haegnim·2023년 7월 13일
0

TIL

목록 보기
37/52

어제 작업을 이어서 로그인과 회원가입, 로그아웃을 구현했다.

트러블 슈팅

라우터간 페이지 전환 시 깜빡거림

어제는 이걸 로딩화면으로 가렸는데 기술 매니저님께 여쭤보니 라우터간 이동시 깜빡거림은 있어서는 안되는 일이라고 말씀하셨다. 결국 문제가 있었다. 매니저님께 설명을 하면서 로딩화면을 주석처리했는데 해결이 되는 것 처럼 보였다. 여기서 실마리를 잡았다.

isLoading에 div태그와 텍스트를 넣은게 문제였다. 짧은 로딩시간 동안 빠르게 isLoading 안의 요소가 화면에 그려졌다가 사라지는게 깜빡임으로 보였다.

그런데 정말 로딩이 오래걸려서 화면이 비는 상황에는 어떻게 하면 좋을까. 예제 사이트에서는 오류 페이지도 error에 안 넣고 별도의 페이지를 만들던데 참고를 해야겠다.

    const { isLoading, error, card } = useSelector((state) => {
        return state.card;
    });
    useEffect(() => {
        //const timer = setTimeout(() => {
            //setShowLoading(false);
        //}, 800);

        dispatch(__getCard(id));
        //return () => {
            //clearTimeout(timer);
        //};
    }, []);
    
    if (isLoading || showLoading) {
        //return <Loading />; 
    }
    if (error) {
        //return <div>{error.message}</div>;
    }


로그인/로그아웃 시 자동 페이지 전환 안됨

다른 분의 코드를 참고하여 Router.jsx에 로그인 인가를 받았을 때만 메인 컨텐츠를 열람가능하도록 구현했다. 참고한 코드는 인가를 state에 저장했다.
문제는 로그인을 하고나면 토큰을 발급받은 상태라서 '/'으로 돌아가면 안되고 로그아웃을 하면 토큰을 제거한 상태라서 '/card'에 남아있으면 안되는데 두 상황 다 페이지 전환이 이뤄지지 않았다.

Router.jsx

    const AuthRoutes = ({ isAuth }) => {
        return !isAuth ? <Outlet /> : <Navigate to={'/card'} />;
    };
    const UserRoutes = ({ isAuth }) => {
        return isAuth ? <Outlet /> : <Navigate to={'/'} />;
    };
    return (
        <Routes>
            <Route element={<AuthRoutes isAuth={auth} />}>
                <Route path="/" element={<Home />} />
                <Route path="/login" element={<Login />} />
                <Route path="/join" element={<Register />} />
            </Route>
            <Route element={<UserRoutes isAuth={auth} />}>
                <Route path="/card" element={<Cards />} />
                <Route path="/card/:id" element={<Card />} />
                <Route path="/card/:id/update" element={<UpdateCard />} />
                <Route path="/card/add" element={<AddCard />} />
            </Route>
        </Routes>
    );

먼저 해 본 시도는 submit이 이뤄질 때 페이지 전환을 하는 것이다.
async & await를 써서 로그인 정보가 넘어간 다음 useNavigate를 이용해 페이지 전환을 한다.

이 시도는 불발되었다.
토큰이 발급됨을 업데이트 못했는 지 '/card'가 아니라 '/'로 되돌아가진다. 새로고침을 해야 다시 '/card'로 간다.

Login.jsx

    const onSubmitHandler = async (e) => {
        e.preventDefault();
        const loginUser = {
            id: userId,
            password,
        };
        await login(loginUser);
        setUserId('');
        setPassword('');
        navigate('/card')
    };

결국 이 방법 뿐인가.
리덕스를 썼다. ㅋㅋㅋㅋㅋㅋㅋㅋ
인가를 받는 함수에 인가를 받으면 true를 에러가 뜨면 false를 리턴하도록 했다.
Router.jsx에서 인가 함수의 결과를 dispatch로 보내고 리듀서에서 결과를 저장하도록 한다.
Login.jsx에도 dispatch를 써서 인가 함수의 결과를 리듀서로 보낸다. 상태 변화가 생기면 Router.jsx가 리렌더링되므로 로그인/로그아웃 시 페이지 전환이 이뤄진다.

auth.js

const authCheck = async () => {
    const accessToken = localStorage.getItem('accessToken');
    try {
        await axios.get(`http://3.38.191.164/user`, {
            headers: {
                authorization: `Bearer ${accessToken}`,
            },
        });
        return true;
    } catch (error) {
        if (error.response.status === 401) {
            localStorage.removeItem('accessToken');
        }
        return false;
    }
};

Router.jsx

    const auth = useSelector((state) => state.auth.isAuth);
    const dispatch = useDispatch();
    useEffect(() => {
        const checkIsAuth = async () => {
            try {
                const authResult = await authCheck();
                dispatch(isAuthCheck(authResult));
            } catch (e) {
                dispatch(isAuthCheck(false));
            }
        };
        checkIsAuth();
        if (auth) {
            return;
        }
    }, [auth]);

Login.jsx

    const onSubmitHandler = async (e) => {
        e.preventDefault();
        const loginUser = {
            id: userId,
            password,
        };
        await login(loginUser);
        setUserId('');
        setPassword('');
        const authResult = await authCheck();
        dispatch(isAuthCheck(authResult));
    };

➕추가
로그아웃 버튼은 헤더에 만들었다.
사실 로그인/회원가입도 헤더 쪽에 있는게 자연스럽다고 생각한다.
인가를 받은 상황이면 로그아웃 버튼이 보이고 아니라면 버튼이 그려지지 않는다.
컴포넌트 구조가 헤더와 라우터가 동급으로 있는 상황이라 전역 상태 관리를 사용했다.
로그인 여부에 따라 ui가 달라지는 건 활용도가 높다고 생각해서 이렇게 한 것도 있다.
기실 첨부터 이렇게 구현할 줄 알았으면 로그인 안되었을 때 수정/삭제 버튼을 가리고 '/card'페이지를 메인으로 사용했을 텐데 ㅎㅎㅎㅎㅎ

const Header = () => {
    const auth = useSelector((state) => state.auth.isAuth);
    const dispatch = useDispatch();
    const logoutOnClick = async () => {
        await localStorage.removeItem('accessToken');
        const authResult = await authCheck();
        dispatch(isAuthCheck(authResult));
    };
    return (
        <HeaderSt>
            <Link to="/">
                <AiOutlineHome size="24" />
            </Link>
            {auth ? <button onClick={logoutOnClick}>로그아웃</button> : null}
        </HeaderSt>
    );
};

0개의 댓글