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>