NODE.JS

Social Media 만들기 - 5) logout 기능 만들기 (Header)

dodop 2021. 7. 6. 12:39

 

header를 만들고 그 안에 logout기능을 만들어보자. 

 

component>Header.js를 만들어주고 App.js에 넣어준다. 

    <div className="main">
          {auth.token && <Header/>}

여기서 로그인페이지로 가도 로그인 되어있다면 페이지 이동하도록 login.js를 수정해준다. 

import { useDispatch, useSelector } from 'react-redux';
import { Link , useHistory} from 'react-router-dom';


     const {auth} = useSelector(state => state);
     const history = useHistory();

     useEffect(() => {
        if(auth.token) history.push("/")
    }, [auth.token, history])

 

이제 헤더파일을 작성해준다. 

여기서 navbar는 bootstrap에서 복사하는데, 

index.html의 부트스트랩을 맞춰준다. 

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css">
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js"></script>
    
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" rel="stylesheet">

 

header.js

import React from 'react'
import { useDispatch, useSelector } from 'react-redux';
import {Link, useLocation} from 'react-router-dom';
import { logout } from '../redux/actions/authActions';

const Header = () => {
    const navLinks = [
        {label:'Home', icon:'home', path:'/'},
        {label:'Message', icon:'near_me', path:'/message'},
        {label:'Discover', icon:'explore', path:'/discover'},
        {label:'Notify', icon:'favorite', path:'/notify'},
    ]

    const {auth, theme} = useSelector(state => state)
    const dispatch = useDispatch()

    const {pathname} = useLocation()

    const isActive = (pn) =>{
        if(pn ===pathname){
            return 'active'
        }
    }


    return (
        <nav className="navbar navbar-expand-lg navbar-light bg-light justify-content-between align-middle">
            <Link  to="/">
                <h1 className="navbar-brand text-uppercase p-0 m-0" >Social Network</h1></Link>
            <button className="navbar-toggler" type="button" data-toggle="collapse" 
            data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" 
            aria-expanded="false" aria-label="Toggle navigation">
                <span className="navbar-toggler-icon"></span>
            </button>

            <div className="menu" >
                <ul className="navbar-nav flex-row">
                    {
                        navLinks.map((link, index)=>(
                            <li className={`nav-item px-2 ${isActive(link.path)}`} key={index}>
                                <Link className="nav-link" to={link.path}>
                                    <span className="material-icons">{link.icon}</span>
                                </Link>
                            </li>
                        ))
                    }

                    <li className="nav-item dropdown" style={{opacity: 1}} >
                        <span className="nav-link dropdown-toggle" id="navbarDropdown" 
                        role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                            <img src={auth.user.avatar} alt="avatar" className="avatar" style={{filter: `${theme ? 'invert(1)': 'invert(0)'}`}}/>
                        </span>

                        <div className="dropdown-menu" aria-labelledby="navbarDropdown">

                            <Link className="dropdown-item" to={`/profile/${auth.user_id}`}>Profile</Link>
                            <label className="dropdown-item" htmlFor="theme">{theme ? "Light mode":'Dark mode'}</label>
                            <div className="dropdown-divider"></div>
                            <Link className="dropdown-item" to="/" onClick={()=>dispatch(logout())}>Logout</Link>
                        </div>
                    </li>
                </ul>

            </div>                  
        </nav>        
    )
}

export default Header

 

 

index.css 에 디자인 추가

img{
  object-fit: cover;
}

.avatar {
 width: 30px ;
 height: 30px ; 
 border-radius: 50% ;
 border: 2px solid black;
}

/* ------AUTH--------- */
@import url("./styles/auth.css");

/* ------LOADING--------- */
@import url("./styles/loading.css");

/* ------LOADING--------- */
@import url("./styles/header.css");

 

 

 

 

logout의 기능을 위해서 action을 설정해준다. 

export const logout = () =>async (dispatch) =>{

    try{
        localStorage.removeItem('firstLogin')

        await postDataAPI('logout')
        window.location.href="/"
    } catch (err) {
        dispatch({ 
            type: GLOBALTYPES.ALERT, 
            payload: {
                error: err.response.data.msg
            } 
        })
    }}

 

추가로 theme의 속성을 사용하기 위해서 (mode 변경)

globaltype을 추가해준다.

export const GLOBALTYPES={
    AUTH:"AUTH",
    ALERT:"ALERT",
    THEME:"THEME"
}

themReducer를 생성하고 추가

import {GLOBALTYPES} from '../actions/globalTypes';

const initialState = false;

const themeReducer = (state=initialState, action) =>{
    switch(action.type){
        case GLOBALTYPES.THEME:
            return action.payload;
        default :
            return state;
    }

}

export default themeReducer;

index.js/reducer에 추가해준다.

import { combineReducers } from "redux";
import auth from './authReducers';
import alert from './alertReducer';
import theme from './themeReducer';

export default combineReducers({
    auth,
    alert,
    theme
})

 

 

추가로 아이콘의 설정을 따로 꺼내서 정의해준다. 

component>Avatar.js생성

import React from 'react'
import { useSelector } from 'react-redux'

const Avatar = ({src}) => {
    const {theme} = useSelector(state => state)
    return (
        <img src={src} alt="avatar" className="avatar" style={{filter: `${theme ? 'invert(1)': 'invert(0)'}`}}/>
    )
}

export default Avatar

header.js에 다음과 같이 변경해준다.

import Avatar from '../components/Avatar';

                    <li className="nav-item dropdown" style={{opacity: 1}} >
                        <span className="nav-link dropdown-toggle" id="navbarDropdown" 
                        role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                            <Avatar src={auth.user.avatar} />
                        </span>

로그아웃도 잘 된다.