#typescript #next-js #tailwindcss

로그아웃 기능 추가하기

Oct 31, 2022


상단바 UI 생성

import axios from 'axios';
import Link from 'next/link'
import React from 'react'
import { useAuthDispatch, useAuthState } from '../context/auth'

const NavBar: React.FC = () => {
    const { loading, authenticated } = useAuthState();
    const dispatch = useAuthDispatch();

    const handleLogout = () => {
        axios.post("/auth/logout")
        .then(() => {
            dispatch("LOGOUT");
            window.location.reload();
        })
        .catch((error) => {
            console.log(error);
        })
    }

    return (
        <div className='fixed inset-x-0 top-0 z-10 flex items-center justify-between h-16 px-5 bg-white'>
            <span className='text-2xl font-semibold text-gray-400'>
                <Link href="/">Community</Link>
            </span>
            <div className='max-w-full px-4'>
                <div className='relative flex items-center bg-gray-100 border rounded hover:border-gray-700 hover:bg-white'>
                    <input
                        type="text"
                        placeholder="Search..."
                        className='px-3 py-1 bg-transparent rounded focus:outline-none'
                    />
                </div>
            </div>

            <div className='flex'>
                {!loading && (
                    authenticated ? (
                        <button className='w-20 p-2 mr-2 text-center text-white bg-gray-400 rounded'
                        onClick={handleLogout}>
                            로그아웃
                        </button>
                    ) : (<>
                        <Link href="/login">
                            <a className='w-20 p-2 mr-2 text-center text-blue-500 border border-blue-500 rounded'>
                                로그인
                            </a>
                        </Link>
                        <Link href="/register">
                            <a className='w-20 p-2 text-center text-white bg-gray-400 rounded'>
                                회원가입
                            </a>
                        </Link>
                    </>)
                )}
            </div>
        </div>
    )
}

export default NavBar

이후 상단바 UI를 reddit-clone-app\client\src\pages\_app.tsx 파일에 추가한다.

import '../styles/globals.css'
import type { AppProps } from 'next/app'
import Axios from 'axios'
import { AuthProvider } from '../context/auth';
import NavBar from '../components/NavBar';

function MyApp({ Component, pageProps }: AppProps) {

  Axios.defaults.baseURL = process.env.NEXT_PUBLIC_SERVER_BASE_URL + "/api";
  Axios.defaults.withCredentials = true;
  
  return <AuthProvider>
    // 추가 부분
    <NavBar />
    <div className="pt-12">
      <Component {...pageProps} />
    </div>
  </AuthProvider>
}

export default MyApp


Logout 핸들러 추가

reddit-clone-app\server\src\routes\auth.ts 파일에 아래 내용을 추가한다.
/api/auth/logout 요청이 서버로 들어왔을 때 동작을 정의한다.

...생략
// 추가 부분
const logout = async (_ : Request, res: Response) => {
    res.set(
        "Set-Cookie",
        cookie.serialize("token", "", {
            httpOnly: true,
            secure: process.env.NODE_ENV === "production",
            sameSite: "strict",
            expires: new Date(0),
            path: "/"
        })
    );
    res.status(200).json({ success: true });
}

const router = Router();
router.get("/me", userMiddleware, authMiddleware, me);
router.post("/register", register);
router.post("/login", login);

// 추가 부분
router.post("/logout", userMiddleware, authMiddleware, logout);
...생략

로그아웃 버튼 동작 구현

reddit-clone-app\client\src\components\NavBar.tsx 파일에 아래 내용을 추가한다.

... 생략
import { useAuthDispatch, useAuthState } from '../context/auth'

const NavBar: React.FC = () => {
    const { loading, authenticated } = useAuthState();
    const dispatch = useAuthDispatch();

    // 로그아웃 버튼 클릭 시 동작
    const handleLogout = () => {
        axios.post("/auth/logout")
        .then(() => {
            dispatch("LOGOUT");
            window.location.reload();
        })
        .catch((error) => {
            console.log(error);
        })
    }
... 생략

            <div className='flex'>
                {!loading && (
                    authenticated ? (
                        <button className='w-20 p-2 mr-2 text-center text-white bg-gray-400 rounded'
                        // 추가 부분
                        onClick={handleLogout}>
                            로그아웃
                        </button>
                    ) : (<>
                        <Link href="/login">
                            <a className='w-20 p-2 mr-2 text-center text-blue-500 border border-blue-500 rounded'>
                                로그인
                            </a>
                        </Link>
                        <Link href="/register">
                            <a className='w-20 p-2 text-center text-white bg-gray-400 rounded'>
                                회원가입
                            </a>
                        </Link>
                    </>)
                )}
            </div>
        </div>
    )
}    

로그아웃 테스트

로그인된 상태로 localhost:3000 진입한다.
로그아웃 버튼을 클릭하면 로그인, 회원가입 버튼이 나타나며 로그아웃 버튼이 사라지게 된다.



*****

© 2021, Ritij Jain | Pudhina Fresh theme for Jekyll.