| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- html
- 프론트앤드
- 팀프로젝트
- react
- 코딩테스트
- 해시
- 네트워크
- frontend
- HTML기초
- 크래프톤 정글
- 정렬
- 그리디
- c언어
- 개발자
- Python
- 프론트엔드
- 프로그래머스
- Mini-React
- 알고리즘 기초
- Git
- DFS
- javascript
- 코딩
- 백준
- 혼자 공부해서 개발까지
- 알고리즘
- 그래프
- 정글
- js
- CSS
Archives
- Today
- Total
민혁이의 IT스토리
[Typers 팀프로젝트] 메인페이지 - 메뉴 만들기 본문
오늘 개발 할 파트는 메뉴 입니다

목차
- 컨포넌트 분리
- 코드 리뷰
- 스스로 아쉬운점
컨포넌트 분리
header/
├── _component\nav/
│ ├── mainMenu/
│ │ ├── MainMenu.jsx
│ │ └── style.js
│ └── subMenu/
│ ├── SubMenu.jsx
│ └── style.js
├── Header.js
└── style.js
설명 : 메뉴가 헤더 부분에 위치하고 있기 때문에 헤더에서 부터 하위 컨포넌트도 뻗어 나가도록 파일을 분리하였습니다.
header -> nav -> menu(Main,Sub)
코드 리뷰
<Header/>
내용
: 헤더 컨포넌트는 로고,메뉴,로그인/회원가입 등을 담고 있습니다. 그중에서도 메뉴는 <S.Nav/> 로 되어있는 부분입니다.
코드 보기
더보기
Component
import React, { useState } from 'react';
import S from './style';
import { Link } from 'react-router-dom';
import SubMenu from './_component/nav/subMenu/SubMenu';
import MainMenu from './_component/nav/mainMenu/MainMenu';
const Header = () => {
const mainMeuItems = [// 메인메뉴
{id : 0, title : '타이핑', url : '/'},
{id : 1, title : '커스텀', url : '/'},
{id : 2, title : '랭킹킹', url : '/'},
{id : 3, title : '창작마당',url : '/'}
]
const subMenuItems = [// 서브메뉴
[
{id : 0, title : '긴글연습', url : '/'},
{id : 1, title : '짧은글연습', url : '/'},
{id : 2, title : '낱말연습', url : '/'},
{id : 3, title : '자리연습', url : '/'},
{id : 4 , title : '미니게임', url : '/'},
],
[
{id : 0, title : '문장 커스텀', url : '/'},
{id : 1, title : '단어 커스텀', url : '/'},
],
[
{id : 0, title : '타이핑 랭크전', url : '/'},
{id : 1, title : '랭킹 보기 ', url : '/'},
],
[
{id : 0, title : '타이핑 랭크전', url : '/'},
{id : 1, title : '랭킹 보기 ', url : '/'},
],
]
const [ishover,setIsHover] = useState(false)
const EnterMenu = () =>{
setIsHover(true)
}
const LeaveMenu = () =>{
setIsHover(false)
}
return (
<S.Header>
<S.Logo>
logo
</S.Logo>
<S.Nav
{/*마우스를 hover하면 실행*/}
onMouseEnter={EnterMenu}
{/*마우스를 out하면 실행*/}
onMouseLeave={LeaveMenu}
>
<S.Menu>
{/*mainMeuItems의 개수 만큼 만복*/}
{mainMeuItems.map(MenuItem=>(
<MainMenu MenuItem={MenuItem} />
))}
</S.Menu>
<S.SubMenuBox ishover={ishover}>
<S.SubMenu>
{/*subMenuItems 개수 만큼 만복*/}
{subMenuItems.map(data=> (
<SubMenu children={data}/>
))}
</S.SubMenu>
</S.SubMenuBox>
</S.Nav>
</S.Header>
);
};
export default Header;
Style
import styled from "styled-components";
import { felxRow } from "../../../../global/common";
const S = {}
S.Header = styled.header`
width: 100%;
height: 110px;
${felxRow}
position: relative;
border-bottom:1px solid #6E58FF ;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
`
S.Main = styled.div`
width: 100%;
height: calc(100vh - 130px);
`
S.Logo = styled.div`
flex: 2;
height: 100%;
text-align: center;
line-height: 130px;
`
S.Nav = styled.div`
flex: 5;
height: 100%;
`
S.Menu = styled.ul`
width: 100;
height: 100%;
display: flex;
justify-content: space-around;
align-items: center;
`
S.SubMenuBox = styled.div`
position: absolute;
top: 101%;
left: 0;
width: 100%;
background-color: #fff;
border-radius: 0 0 20px 20px;
overflow: hidden;
max-height: ${({ ishover }) => (ishover ? '300px' : '0')};
opacity: ${({ ishover }) => (ishover ? '1' : '0')};
transform: translateY(0);
transition: max-height 0.4s ease, opacity 0.4s ease;
border-top: 2px solid transparent;
`
S.SubMenu = styled.div`
width: 50%;
${felxRow}
justify-content: space-around;
margin-left: 20%;
`
S.ButtonContainer = styled.div`
flex: 3;
height: 110px;
right: 0;
`
S.Auth = styled.div`
width: 50%;
height: 100%;
font-size: 20px;
font-weight: 500;
${felxRow}
justify-content: center;
align-items: center;
color: #6E58FF;
& > a{
color: #6E58FF;
}
`
export default S;
<MainMenu/>
header 참고 코드
const mainMeuItems = [// 메인메뉴 url경로 미정
{id : 0, title : '타이핑', url : '/'},
{id : 1, title : '커스텀', url : '/'},
{id : 2, title : '랭킹킹', url : '/'},
{id : 3, title : '창작마당',url : '/'}
]
위와 같은 배열을 <header/> 컨포넌트에서 map을 통해 객체 하나하나를 <MainMenu/>로 props해줍니다.
코드 보기
더보기
Component
const MainMenu = ({MenuItem}) => {
const {id, title , url} = MenuItem
return (
<S.MenuText key={id}><Link to={url}>{title}</Link></S.MenuText>
);
};
Style
const S = {}
S.MenuText = styled.li`
font-size: 25px;
flex: 1;
height: 100%;
text-align: center;
line-height: 110px;
&>a{
display: block;
width: 100%;
height: 100%;
color: #6E58FF;;
}
& > a:hover{
border-bottom: 7px solid #6E58FF;
}
`
<SubMenu/>
header 참고 코드
const subMenuItems = [// 서브메뉴
[
{id : 0, title : '긴글연습', url : '/'},
{id : 1, title : '짧은글연습', url : '/'},
{id : 2, title : '낱말연습', url : '/'},
{id : 3, title : '자리연습', url : '/'},
{id : 4 , title : '미니게임', url : '/'},
],
[
{id : 0, title : '문장 커스텀', url : '/'},
{id : 1, title : '단어 커스텀', url : '/'},
],
[
{id : 0, title : '타이핑 랭크전', url : '/'},
{id : 1, title : '랭킹 보기 ', url : '/'},
],
[
{id : 0, title : '타이핑 랭크전', url : '/'},
{id : 1, title : '랭킹 보기 ', url : '/'},
],
]
구조는 mainMeuItems과 유사하지만 배열이 한번 더 감싸고 있다는 부분이 차이가 있습니다.
코드 보기
더보기
Component
import React from 'react';
import { Link } from 'react-router-dom';
import S from './style';
const SubMenu = ({children}) => {
return (
<ul>
{children.map(data =>(
<S.SubText key={data.id}>
<Link to={data.url}>{data.title}</Link>
</S.SubText>
))}
</ul>
);
};
export default SubMenu;
Style
import styled from "styled-components";
import { parentSize } from "../../../../../../../global/common";
const S = {}
S.SubText = styled.li`
width: 150px;
height: 40px;
& > a{
display: block;
${parentSize}
line-height: 40px;
text-align: center;
color : #6E58FF;
}
`
export default S;
완성 영상
동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.
스스로 아쉬웠던 점
메인메뉴와 서브메뉴를 만들 때 객체를 사용하였는데,
객체의 구조가 크게 다르지 않아서 메뉴 컨포넌트를 하나 만들어서
코드 재사용성이 높은 컨포넌트를 만드는게 좋았을 것
같다는 생각이 이 글을 작성하면서 들었습니다..
하지만 또 메인메뉴와 서브메뉴를 나누는 것도 나쁘지 않다는 생각이 들어서
구현은 끝냈지만 완성이 덜 된 느낌이였습니다.
