[React] Navbar (feat. Dropdown Menu)

Yoochan·2022년 2월 22일
1

처음에 구상했던 Navbar의 디자인이다. 해당 디자인의 Navbar 구현 자체는 어렵지 않았다. 하지만 프로필을 눌렀을 때 드롭다운 메뉴들을 보여주는 부분은 신경쓸 필요가 있었다.

semantic-ui Dropdown 공식문서
https://react.semantic-ui.com/modules/dropdown/

Dropdown 구현 방법은 여러가지가 있지만 나는 그 중에서 semantic-ui에 있는 Dropdown을 이용했다. 공식문서를 참고하면 어떤 식으로 Dropdown 메뉴들을 구현하는지 예시도 나와있고, 해당 컴포넌트에 전달할 수 있는 props 목록들도 잘 설명되어있다.

Dropdown 전체를 구성한다. trigger가 따로 없으면 그냥 작은 드롭다운 아이콘을 누를 때 드롭다운이 된다. 하지만 우리 페이지의 디자인은 아이콘을 누를 때도 드롭다운이 되도록 만들어야했다. 이때 이 trigger라는 인자를 이용해 이를 해결했다.

const trigger = (
    <span>
      <Avatar
        src={user?.user.avatar ? user.user.avatar : `${process.env.PUBLIC_URL}/images/missing.png`}
        style={{ cursor: 'pointer' }}
      />
    </span>
  );

다음과 같이 trigger을 선언하고 props로 전달하면 된다.

<Dropdown
  direction="left"
  trigger={trigger}
  style={{ display: 'flex', alignItems: 'center' }}
>
...

Dropdown.Menu의 하위 컴포넌트에 드롭다운 메뉴에 들어갈 Dropdown.Item 아이템들이 구성된다. 해당 아이템들의 텍스트가 DropText로 구성된다.

나는 정말 간단하게 사용한 정도지만 페이지를 참고하면 거의 원하는 드롭다운 메뉴들은 다 구현할 수 있어보였다.

코드

Navbar는 fixed를 이용해 제일 맨 위 상위로 고정시켰다.

// src/components/Navbar/DesktopNabar.jsx
import React, { useRef, useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import styled, { css } from 'styled-components';
import { Icon, Dropdown } from 'semantic-ui-react';
import COLOR from 'constants/color.constant';
import { darken } from 'polished';
import { SET_TYPE } from 'reducers/postListType';

const Nav = styled.nav`
  position: fixed;
  top: 0;
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: white;
  padding: 0.85rem 2rem;
  margin-bottom: 4rem;
  z-index: 1;
  box-shadow: 1px 1px 10px -5px black;
`;

const Avatar = styled.img`
  width: 2rem;
  height: 2rem;
  margin-left: 0.5rem;
  border-radius: 50%;
`;

const DropText = styled.div`
  font-weight: 500 !important;
`;

const Login = styled.button`
  background: ${COLOR.PRIMARY} !important;
  color: white !important;
  font-family: 'NS-R' !important;
  height: 2rem;
  font-size: 14px !important;
  letter-spacing: 0.1rem;
  border-radius: 0.3rem;
  padding: 0 1rem;
  cursor: pointer;
  &:hover {
    background: ${darken(0.03, COLOR.PRIMARY)} !important;
  }
`;

const Logo = styled.img`
  cursor: pointer;
  width: 7rem;
  height: auto;
`;


const DesktopNavbar = () => {
  const navigate = useNavigate();
  const { user } = useSelector((state) => state.authentication);



  const handleSignOut = () => {
    localStorage.removeItem('user');
    window.location.replace('/');
  };

  const trigger = (
    <span>
      <Avatar
        src={user?.user.avatar ? user.user.avatar : `${process.env.PUBLIC_URL}/images/missing.png`}
        style={{ cursor: 'pointer' }}
      />
    </span>
  );

  return (
    <Nav>
     	// ...
    
         <Icon
          name="search"
          style={{ fontSize: '1.5rem', marginRight: '0.5rem', cursor: 'pointer' }}
        /> 
        {user ? (
          <>
            <Icon
              name="pencil alternate"
              style={{ fontSize: '1.5rem', marginLeft: '0.5rem', cursor: 'pointer' }}
              onClick={() => {
                navigate('/post');
              }}
            />
            <Dropdown
              direction="left"
              trigger={trigger}
              style={{ display: 'flex', alignItems: 'center' }}
            >
              <Dropdown.Menu style={{ marginTop: '1.3rem' }}>
                <Dropdown.Item
                  onClick={() => {
                    navigate('/mypage');
                  }}
                >
                  <DropText>프로필</DropText>
                </Dropdown.Item>

                <Dropdown.Item
                  onClick={() => {
                    navigate('/post');
                  }}
                >
                  <DropText>글쓰기</DropText>
                </Dropdown.Item>

                <Dropdown.Item
                  onClick={() => {
                    navigate('/setting');
                  }}
                >
                  <DropText>설정</DropText>
                </Dropdown.Item>

                <Dropdown.Item onClick={handleSignOut}>
                  <DropText>로그아웃</DropText>
                </Dropdown.Item>
              </Dropdown.Menu>
            </Dropdown>{' '}
          </>
        ) : (
          <Link to="/signin">
            <Login>로그인</Login>
          </Link>
        )}
      </div>
    </Nav>
  );
};

export default DesktopNavbar;

구현 화면 (1)

구현 화면 (2)

profile
FrontEnd Developer

0개의 댓글