- 최근 React로 프로젝트를 진행하며 Side를 구현할 일이 생겼다.
하지만 모두 Ref와 Effect 훅을 사용하여 구현하는데 문제는
모든 요소가 한 컴포넌트에 몰려있어 lean하지 못한 컴포넌트가 탄생한다.
목표
- 네비게이션과 사이드 바 메뉴 컴포넌트는 따로 구성하기
- 직관적인 코드로 작성하기
구동방식
- 우선 변경사항이 있으니 state를 선언, 네비 컴포넌트(부모요소)에서 클릭을 하면 setState를 true로 바꾸어준다.
- 사이드바 컴포넌트(자식 요소)에서
X
를 클릭하면 다시 state를 false로 만들어준다.
- 요 state를 기반으로 classname을 동적으로 부여한다. 끝
Navigation.js
- 가장 최상단에서 고정되어있을 네비게이션 메뉴 bar로 어떤 페이지에서든 메뉴버튼을 클릭하여 바로 다양한 페이지에 접근이 가능하도록 설계하였다.
import classes from "./Navigation.module.css";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faBars} from "@fortawesome/free-solid-svg-icons";
import {useState} from "react";
import Sidebar from "./Sidebar";
const Navigation = props => {
const [menuOn, setMenuOn] = useState(false);
const menuOffTrigger = () => {
setMenuOn(false);
}
const menuOnTrigger = () => {
setMenuOn(true);
}
const menuOnClass = classes.menuOn;
const menuOffClass = classes.menuOff;
return (
<div className={classes.navigation}>
<div className={classes.wrapper}>
<div className={`${menuOn ? menuOnClass : menuOffClass}`}>
<Sidebar onMenuOff={menuOffTrigger}/> <== 요게 사용자정의 컴포넌트
</div>
<div className={classes.menuIcon}>
<FontAwesomeIcon icon={faBars} className={classes.menu}
onClick={menuOnTrigger}/></div>
<div>
<span>사용자이름</span>
<span>사진</span>
<span>로그인</span>
</div>
</div>
</div>
)
}
export default Navigation;
import classes from "./Sidebar.module.css";
import comLogo from "../../assets/img/comLogo.png"
import userImg from "../../assets/img/img3.png"
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faX} from "@fortawesome/free-solid-svg-icons";
import {useRef} from "react";
const Sidebar = props => {
return (
<section className={classes.sidebar}>
<div className={classes.left}><FontAwesomeIcon onClick={props.onMenuOff} icon={faX}/></div> <== 요기에 onClick
<div className={classes.comLogo}>
...
</section>
)
}
export default Sidebar;
Css
- 별로 궁금해 하진 않겠지만 혹시 몰라 css를 남겨본다
Navigation css
.navigation {
display: flex;
width: 100%;
border: black 1px solid;
justify-content: center;
position: fixed;
z-index: 99;
background-color: white;
}
.wrapper {
width: 80%;
height: 3rem;
display: flex;
align-items: center;
justify-content: space-between;
background-color: white;
position: relative;
}
.menuIcon{
display: flex;
position: absolute;
left: 0;
}
.menu {
cursor: pointer;
}
.menuOn {
transition: 1s;
transform: translateX(210px);
}
.menuOff {
transition: 1s;
transform: translateX(-210px);
}
.left {
display: flex;
justify-content: right;
cursor: pointer;
}
.sidebar {
position: absolute;
left: -370px;
top: 0px;
width: 200px;
height: 95vh;
padding: 2%;
background-color: white;
border-radius: 5vh;
border: black solid 0.5px;
}
.wrapper {
z-index: 99;
}
.comLogo {
display: flex;
justify-content: center;
margin-bottom: 1rem;
}
.circle {
height: 6rem;
width: 6rem;
margin: 0 auto;
border: black solid 1px;
border-radius: 3rem;
cursor: pointer;
}
.comDesc {
font-weight: bolder;
font-size: large;
margin-bottom: 1rem;
}
.menuBar {
display: flex;
width: 100%;
height: 3rem;
border: black solid;
border-width: 1px 0;
margin: 1%;
align-items: center;
cursor: pointer;
}
.logContainer{
position: absolute;
bottom: 50px;
left: 0px;
padding: 1rem;
}
.userContainer {
display: flex;
justify-content: center;
}
.userImg{
width: 3rem;
height: 3rem;
border-radius: 1.5rem;
overflow: hidden;
border: solid black 1px;
margin: 1rem auto;
cursor: pointer;
}
.userInfo {
width: 5rem;
padding: 0 1rem;
cursor: pointer;
}
.footer {
margin-top: 1rem;
font-size: smaller;
color: gray;
}